go中方法的接收者是值或者指针的区别
type T struct { Name string
}
func (t T) M1() { t.Name = "name1"
}
func (t *T) M2() { t.Name = "name2"
}
M1() 的接收者是值类型 T, M2() 的接收者是值类型 *T , 两个方法内都是改变Name值。
下面声明一个 T
类型的变量,并调用 M1()
和 M2()
。
t1 := T{"t1"} fmt.Println("M1调用前:", t1.Name) t1.M1() fmt.Println("M1调用后:", t1.Name) fmt.Println("M2调用前:", t1.Name) t1.M2() fmt.Println("M2调用后:", t1.Name)
输出结果为:
M1调用前: t1 M1调用后: t1 M2调用前: t1 M2调用后: name2
先来约定一下:接收者可以看作是函数的第一个参数,即这样的: func M1(t T)
, func M2(t *T)
。 go不是面向对象的语言,所以用那种看起来像面向对象的语法来理解可能有偏差。
当调用 t1.M1()
时相当于 M1(t1)
,实参和行参都是类型 T,可以接受。此时在M1()中的t只是t1的值拷贝,所以M1()的修改影响不到t1。
当调用 t1.M2()
=> M2(t1)
,这是将 T 类型传给了 *T 类型,go可能会取 t1 的地址传进去: M2(&t1)
。所以 M2() 的修改可以影响 t1 。
T 类型的变量这两个方法都是拥有的。
下面声明一个 *T
类型的变量,并调用 M1()
和 M2()
。
t2 := &T{"t2"} fmt.Println("M1调用前:", t2.Name) t2.M1() fmt.Println("M1调用后:", t2.Name) fmt.Println("M2调用前:", t2.Name) t2.M2() fmt.Println("M2调用后:", t2.Name)
输出结果为:
M1调用前: t2 M1调用后: t2 M2调用前: t2 M2调用后: name2
t2.M1()
=> M1(t2)
, t2 是指针类型, 取 t2 的值并拷贝一份传给 M1。
t2.M2()
=> M2(t2)
,都是指针类型,不需要转换。
*T 类型的变量也是拥有这两个方法的。