type attr struct{perm int}type file struct{name stringattr // 仅有类名}var f filef.name = "lvmenglou"f.perm = 24 // 等价于f.attr.perm = 24
type user struct{}type manager struct{user // 匿名字段}func (user) toString() string{return "user"}func (m manager) toString() string{return m.user.toString() + ";manager"}func main(){var m managerprintln(m.toString()) // 输出:user;managerprintln(m.user.toString()) // 输出:user}
func (ms MyStruct) String() string // value methodsfunc (ms *MyStruct) String() string // pointer methods
值方法(value methods)可以通过指针和值调用,但是指针方法(pointer methods)只能通过指针来调用。
但有一个例外,如果某个值是可寻址的(addressable,或者说左值),那么编译器会在值调用指针方法时自动插入取地址符,使得在此情形下看起来像指针方法也可以通过值来调用。
type Foo struct {name string}func (f *Foo) PointerMethod() {fmt.Println("pointer method on", f.name)}func (f Foo) ValueMethod() {fmt.Println("value method on", f.name)}func NewFoo() Foo { // 返回一个右值,不可寻址return Foo{name: "right value struct"}}func main() {f1 := Foo{name: "value struct"}f1.PointerMethod() // 编译器会自动插入取地址符,变为 (&f1).PointerMethod()f1.ValueMethod()f2 := &Foo{name: "pointer struct"}f2.PointerMethod()f2.ValueMethod() // 编译器会自动解引用,变为 (*f2).PointerMethod()NewFoo().ValueMethod()NewFoo().PointerMethod() // Error!!!}
func (f *Foo) PointerMethod() {fmt.Println("pointer method on ", f.name)}func (f Foo) ValueMethod() {fmt.Println("value method on", f.name)}
func PointerMethod(f *Foo) {fmt.Println("pointer method on ", f.name)}func ValueMethod(f Foo) {fmt.Println("value method on", f.name)}
方法是否需要修改receiver本身。如果需要,那receiver必然要是指针。
效率问题。如果receiver是值,那在方法调用时一定会产生 struct 拷贝,而大对象拷贝代价很大。
一致性。对于同一个struc 的方法,value method和pointer method混杂用肯定是优雅。
type N intfunc (n N) value() { // value methodn++fmt.Printf("v:%p, %v\n", &n, n)}func (n *N) pointer() { // point method(*n)++fmt.Printf("p:%p, %v\n", n, *n)}func main() {var a N = 5a.value()a.pointer()fmt.Printf("a:%p,%v\n", &a, a)}
v: 0x8200741c8, 26 // 虽然n被打印为26,但是在main()中,n的值还是25,未修改!!!p: 0x8200741c0, 26a: 0x8200741c0, 26 // n的值被修改为26,是通过a.pointer()修改的!!!
type S struct{}type T struct{S // 匿名嵌入字段}func (S) sVal() {}func (*S) sPtr() {}func (T) sVal() {}func (*T) sPtr() {}func methodSet(a interface()) {t := reflect.TypeOf(a)for i, n := 0, t.NumMethod(); i < n; i++ {m := t.Method(i)fmt.Println(m.Name, m.Type)}}func main() {var t TmethodSet(t) // 显示T方法集println("---------------")methodSet(&t) // 显示*T方法集}
sVal func(main.T)tVal func(main.T)----------------sPtr func(*main.T)sVal func(*main.T)tPtr func(*main.T)tVal func(*main.T)
类型T方法集包含所有的receive T方法;
类型*T方法集包含所有receive T + *T方法;
匿名嵌入S,T方法集包含所有receive T方法;
匿名嵌入*S,T方法集包含所有receive S + *S方法;
匿名嵌入S或*S,*T方法集包含所有receive S + *S方法。