oop
go 不同文件之间的引用
同一个包里面,不同文件之间,不需要 import,直接用就好。不同包的话,需要引用包,只能使用大写字母开头的方法 ,变量等等,小写子母开头的只能包内使用。
method
method 是附属在一个给定的类型上的,他的语法和函数的声明语法几乎一样,只是在 func后面增加了一个 receiver (也就是 method 所依从的主体)
package main
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Circle struct {
r float64
}
func (r Rectangle) area() float64 {
r.height += 1
return r.height * r.width
}
func (c Circle) area() float64 {
return c.r * c.r * math.Pi
}
func main() {
x := Rectangle{1.0, 2.0}
y := Circle{1.0}
fmt.Println(x.area()) //2
fmt.Println(y.area()) //3.141592653589793
//注意, 在 Rectangle 的 area method 中给 height 属性加一, 但是 x.height 仍然是原来的值, 说明这里的 Receiver 是值传递的
fmt.Println(x.height) //2
}
注意
虽然 method 的名字一模一样,但是如果接收者不一样,那么method就不一样
method 里面可以访问接收者的字段, 但是若不显式声明 Receiver 为指针的话,则为值传递,method 中的行为不会影响调用 method 的对象成员的值
指针作为 receiver
package main
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Circle struct {
r float64
}
func (r *Rectangle) area() float64 {
// go 语言可以自动解一层引用, 所以这里既可以用 r.height += 1 又可以用 (*r).height += 1 其他语句同理
r.height += 1
return r.height * r.width
}
func (c *Circle) area() float64 {
c.r -= 1
return c.r * c.r * math.Pi
}
func main() {
x := Rectangle{1.0, 2.0}
y := Circle{1.0}
// go 语言可以自动加一层 &, 所以这里既可以用 x.area() 调用又可以 (&x).area() 调用, 其他语句同理
fmt.Println(x.area()) //3
fmt.Println(y.area()) //0
// receiver 传的指针, 所以 x.height 和 y.r 都被改变了
fmt.Println(x.height) //3
fmt.Println(y.r) //0
}
注意
go 语言可以自动进行一层的引用或者解引用转换,既,如果一个 method 的 receiver 是 T, 你可以在一个 T 类型的实例变量 V 上面调用这个 method,而不需要 &V 去调用这个 method。也可以在这个 method 内直接用 receiver.x 访问变量 V 的 x 成员,而不需要 (receiver).x 去访问 V 的 x 成员
receiver 只能是单层指针,不能是双指针或者多层指针,也不能是一个指针类型变量的指针
method 继承
method 是可以继承的。如果匿名字段实现了一个 method,那么包含这个匿名字段的 struct 也能调用该 method
package main
import (
"fmt"
)
type Human struct {
name string
age int
phone string
}
type student struct {
h Human
school string
}
type Employee struct {
Human //匿名字段
company string
}
func (h *Human) sayHi() {
fmt.Println("hello world")
}
func main() {
a := Human{"yuan", 18, "123"}
b := student{a, "jxust"}
c := Employee{a, "baidu"}
a.sayHi() //hello world
// struct 只能继承匿名字段的 method
// b.sayHi() //b.sayHi undefined (type student has no field or method sayHi)
//对于非匿名的字段可以通过字段间接访问 method
b.h.sayHi() //hello world
c.sayHi() //hello world
}
注意
struct 只能继承匿名字段的 method, 对于非匿名的字段可以通过字段间接访问 method
method 重写
上面的例子中,如果 student 想要实现自己的 SayHi, 怎么办?简单,和匿名字段冲突一样的道理,我们可以在 student 上面定义一个 method,重写了匿名字段的方法
package main
import (
"fmt"
)
type Human struct {
name string
age int
phone string
}
type student struct {
h Human
school string
}
func (h *Human) sayHi() {
fmt.Println("hello world")
}
func (s *student) sayHi() {
fmt.Println("hi, i am a student")
}
func main() {
a := Human{"yuan", 18, "123"}
b := student{a, "jxust"}
a.sayHi() //hello world
b.sayHi() //hi, i am a student
}