按照Go语言语法规范的说法,Go的method是一个带了一个receiver的function。这个receiver的作用和C++的class member function的this指针很相似。但是receiver不一定要是指针类型,也可以是一个值类型;比如下面这个例子:
package main import "fmt" type Int int func (i *Int) PrintAndIncrementWithPointer() { fmt.Printf("%d ", *i) (*i)++ } func (i Int) PrintAndIncrementWithValue() { fmt.Printf("%d ", i) i++ } func main() { var p *Int = new(Int) *p = 10 p.PrintAndIncrementWithPointer() fmt.Printf("%d ", *p) p.PrintAndIncrementWithValue() fmt.Printf("%d ", *p) var a Int = 20 a.PrintAndIncrementWithPointer() fmt.Printf("%d ", a) a.PrintAndIncrementWithValue() fmt.Printf("%d ", a) }
从这个例子可以看出来,即便PrintAndIncrementWithPointer的receiver是Int指针,但是用指针(pointer)和用值(value)都可以调用它(第26行和第32行)。类似的,即便PrintAndIncrementWithValue的receiver是Int,但是用指针和值都能调用它(第28行和第34行)。
那么难道receiver是指针和值是没有区别的嘛?不是的。在Go FAQ中有解释:
When defining a method on a type, the receiver (s in the above example) behaves exactly is if it were an argument to the method. Define the method on a pointer type if you need the method to modify the data the receiver points to. Otherwise, it is often cleaner to define the method on a value type.
意思是:如果reciever是指针,那么method就可以修改receiver指向的值的内容;否则修改对调用者无效。这也可以从上面程序的输出结果得到验证:
10 11 11 11 20 21 21 21
这个运行结果说明,第9行的++是对调用者(main)拥有的*p和a起了作用的;而第14行的++则没有改变调用者拥有的数据。
上述区别类似于C++中的const/non-const class member function。上面例子用C++描述,大概是这样的:
class Int { public: void PrintAndIncrementWithPointer() { std::cout << a_ << " "; ++a_; } void PrintAndIncrementWithValue() const { std::cout << a_ << " "; // ++a_; Note here that ++a_ is illegal here in C++ syntax } private: int a_; };
上面这段C++程序提醒我们,C++的class member function还有一个特性,就是外界是否可以调用(public还是protected/private)。“外界是否可以调用”在Go中不是通过专门的关键词来描述的,而是通过method name是否是大写开头(capitalized)来标志的。