第6章,部分字词修订。

This commit is contained in:
zhliner
2017-08-24 22:28:33 +08:00
parent ff3c5b0a70
commit 9a9b9a0594
5 changed files with 13 additions and 13 deletions

View File

@@ -13,7 +13,7 @@ func (p *Point) ScaleBy(factor float64) {
在现实的程序里一般会约定如果Point这个类有一个指针作为接收器的方法那么所有Point的方法都必须有一个指针接收器即使是那些并不需要这个指针接收器的函数。我们在这里打破了这个约定只是为了展示一下两种方法的异同而已。
只有类型(Point)和指向他们的指针`(*Point)`,才可能出现在接收器声明里的两种接收器。此外,为了避免歧义,在声明方法时,如果一个类型名本身是一个指针的话,是不允许其出现在接收器中的,比如下面这个例子:
只有类型(Point)和指向他们的指针`(*Point)`,才可能出现在接收器声明里的两种接收器。此外,为了避免歧义,在声明方法时,如果一个类型名本身是一个指针的话,是不允许其出现在接收器中的,比如下面这个例子:
```go
type P *int
@@ -65,7 +65,7 @@ pptr.Distance(q)
这里的几个例子可能让你有些困惑,所以我们总结一下:在每一个合法的方法调用表达式中,也就是下面三种情况里的任意一种情况都是可以的:
不论接收器的实际参数和其接收器的形式参数相同比如两者都是类型T或者都是类型`*T`
不论接收器的实际参数和其形式参数相同比如两者都是类型T或者都是类型`*T`
```go
Point{1, 2}.Distance(q) // Point
@@ -84,11 +84,11 @@ p.ScaleBy(2) // implicit (&p)
pptr.Distance(q) // implicit (*pptr)
```
如果命名类型T(译注用type xxx定义的类型)的所有方法都是用T类型自己来做接收器(而不是`*T`)那么拷贝这种类型的实例就是安全的调用他的任何一个方法也就会产生一个值的拷贝。比如time.Duration的这个类型在调用其方法时就会被全部拷贝一份包括在作为参数传入函数的时候。但是如果一个方法使用指针作为接收器你需要避免对其进行拷贝因为这样可能会破坏掉该类型内部的不变性。比如你对bytes.Buffer对象进行了拷贝那么可能会引起原始对象和拷贝对象只是别名而已实际上指向的对象是一的。紧接着对拷贝后的变量进行修改可能会有让你意外的结果。
如果命名类型T译注用type xxx定义的类型的所有方法都是用T类型自己来做接收器而不是`*T`那么拷贝这种类型的实例就是安全的调用他的任何一个方法也就会产生一个值的拷贝。比如time.Duration的这个类型在调用其方法时就会被全部拷贝一份包括在作为参数传入函数的时候。但是如果一个方法使用指针作为接收器你需要避免对其进行拷贝因为这样可能会破坏掉该类型内部的不变性。比如你对bytes.Buffer对象进行了拷贝那么可能会引起原始对象和拷贝对象只是别名而已实际上它们指向的对象是一的。紧接着对拷贝后的变量进行修改可能会有让你意外的结果。
**译注:** 作者这里说的比较绕,其实有两点:
1. 不管你的method的receiver是指针类型还是非指针类型都是可以通过指针/非指针类型进行调用的,编译器会帮你做类型转换。
2. 在声明一个method的receiver该是指针还是非指针类型时你需要考虑两方面的内部第一方面是这个对象本身是不是特别大如果声明为非指针变量时调用会产生一次拷贝第二方面是如果你用指针类型作为receiver那么你一定要注意这种指针类型指向的始终是一块内存地址就算你对其进行了拷贝。熟悉C或者C的人这里应该很快能明白。
2. 在声明一个method的receiver该是指针还是非指针类型时你需要考虑两方面的因素第一方面是这个对象本身是不是特别大如果声明为非指针变量时调用会产生一次拷贝第二方面是如果你用指针类型作为receiver那么你一定要注意这种指针类型指向的始终是一块内存地址就算你对其进行了拷贝。熟悉C或者C++的人这里应该很快能明白。
{% include "./ch6-02-1.md" %}