Created
April 11, 2017 07:57
-
-
Save Bingnan/b0c102c676e46b647a05caa4e15592ae to your computer and use it in GitHub Desktop.
go语言中指针或值作为接收者的区别
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10.6.3 指针或值作为接收者 | |
鉴于性能的原因,recv 最常见的是一个指向 receiver_type 的指针(因为我们不想要一个实例的拷贝,如果按值调用的话就会是这样),特别是在 receiver 类型是结构体时,就更是如此了。 | |
如果想要方法改变接收者的数据,就在接收者的指针类型上定义该方法。否则,就在普通的值类型上定义方法。 | |
下面的例子 pointer_value.go 作了说明:change()接受一个指向 B 的指针,并改变它内部的成员;write() 接受通过拷贝接受 B 的值并只输出B的内容。注意 Go 为我们做了探测工作,我们自己并没有指出是是否在指针上调用方法,Go 替我们做了这些事情。b1 是值而 b2 是指针,方法都支持运行了。 | |
示例 10.13 pointer_value.go: | |
package main | |
import ( | |
"fmt" | |
) | |
type B struct { | |
thing int | |
} | |
func (b *B) change() { b.thing = 1 } | |
func (b B) write() string { return fmt.Sprint(b) } | |
func main() { | |
var b1 B // b1是值 | |
b1.change() | |
fmt.Println(b1.write()) | |
b2 := new(B) // b2是指针 | |
b2.change() | |
fmt.Println(b2.write()) | |
} | |
/* 输出: | |
{1} | |
{1} | |
*/ | |
试着在 write() 中改变接收者b的值:将会看到它可以正常编译,但是开始的 b 没有被改变。 | |
我们知道方法不需要指针作为接收者,如下面的例子,我们只是需要 Point3 的值来做计算: | |
type Point3 struct { x, y, z float } | |
// A method on Point3 | |
func (p Point3) Abs float { | |
return math.Sqrt(p.x*p.x + p.y*p.y + p.z*p.z) | |
} | |
这样做稍微有点昂贵,因为 Point3 是作为值传递给方法的,因此传递的是它的拷贝,这在 Go 中合法的。也可以在指向这个类型的指针上调用此方法(会自动解引用)。 | |
假设 p3 定义为一个指针:p3 := &Point{ 3, 4, 5}。 | |
可以使用 p3.Abs() 来替代 (*p3).Abs()。 | |
像例子 10.11(method1.go)中接收者类型是 *TwoInts 的方法 AddThem(),它能在类型 TwoInts 的值上被调用,这是自动间接发生的。 | |
因此 two2.AddThem 可以替代 (&two2).AddThem()。 | |
在值和指针上调用方法: | |
可以有连接到类型的方法,也可以有连接到类型指针的方法。 | |
但是这没关系:对于类型 T,如果在 *T 上存在方法 Meth(),并且 t 是这个类型的变量,那么 t.Meth() 会被自动转换为 (&t).Meth()。 | |
指针方法和值方法都可以在指针或非指针上被调用,如下面程序所示,类型 List 在值上有一个方法 Len(),在指针上有一个方法 Append(),但是可以看到两个方法都可以在两种类型的变量上被调用。 | |
示例 10.14 methodset1.go: | |
package main | |
import ( | |
"fmt" | |
) | |
type List []int | |
func (l List) Len() int { return len(l) } | |
func (l *List) Append(val int) { *l = append(*l, val) } | |
func main() { | |
// 值 | |
var lst List | |
lst.Append(1) | |
fmt.Printf("%v (len: %d)", lst, lst.Len()) // [1] (len: 1) | |
// 指针 | |
plst := new(List) | |
plst.Append(2) | |
fmt.Printf("%v (len: %d)", plst, plst.Len()) // &[2] (len: 1) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment