```go
package model
//A Person class below
//关于包内标识符的可见性,如果以大写字母开头,那么这个标识符对于其他包来说就是可见的,小写则不可见
type Person struct{//一个结构体
longId int;//包外不可见
name string;//包外不可见
age int;//包外不可见
}
func NewPerson(longId int64,name string,age int) *Person{//一般的会提供这样一个方法用于构建对象返回对象指针
return &Person{longId:longId,name:name,age:age}
}
//一般面向对象会这样写,(person *Person)代表这个方法接受*person指针
func (person *Person) SetId(longId int) {
person.longId=longId;
}
//面向过程的写法会这样:上下两个方法实际上在执行的时候并没有什么区别,和Java this指针首先压栈的操作就是一样的;
func SetId2(person *Person,longId int){//SetId2()避免方法名冲突
person.longId=longId;
}
func (person *Person) SetName(name string){
person.name = name;
}
func (person *Person) SetAge(age int){
person.age = age;
}
func (person Person) SetAge2(age int){
person.age = age;
}
//main usage of Person
package main
import (
"model"
"fmt"
)
func main(){
var person *model.Person = new(model.Person);//内建函数new()返回一个类型的指针,这个类型的全部的field都回被初始化默认的值:0,false,"",nil
fmt.Println("person1 *person = ",person);
fmt.Println("========================================");
person2:=model.Person{};//{}一个类型的构造函数
fmt.Println("person2 person = ",person2);
person.SetAge2(11);
fmt.Println("After SetAge2,person2 person = ",person2);
person2.SetAge(11);//这里应该编译不过去啊,因为SetAge接收的是*Person类型,而person2是Person类型,然而却没有问题,这是Golang设计的问题么?
fmt.Println("After SetAge,person2 person = ",person2);
fmt.Println("========================================");
person3:=model.NewPerson(10,"person3",10);//更常用的方式
fmt.Println("person3 *person = ",person3);
person3.SetAge2(11);//这里应该编译不过去啊,因为SetAge接收的是Person类型啊,person3是*Person类型,这是Golang设计的问题么?
fmt.Println("After SetAge2,person3 *person = ",person3);
person3.SetAge(11);
fmt.Println("After SetAge,person3 *person = ",person3);
fmt.Println("========================================");
//person3:=model.Person{10,"person3",100};//注意Person内的field都是invisible的,编译时会报错,尽管IDE可能不会报错;
}
输出:
person1 *person = &{0 0}
========================================
person2 person = {0 0}
After SetAge2,person2 person = {0 0}
After SetAge,person2 person = {0 11}
========================================
person3 *person = &{10 person3 10}
After SetAge2,person3 *person = &{10 person3 10}
After SetAge,person3 *person = &{10 person3 11}
========================================
//考虑到golang的参数传递都是值传递(不论是struct还是基本类型还是pointer类型),SetAge和SetAge2在参数压栈的时候做了什么操作么?类似于Java里面的基本类型及包装类的自动转换?
```
第 1 条附言 ·
站长,int64 粘贴完后怎么有的变成int了 ,还有就是星(*)号也是有的丢有的不丢,奇怪,
@polaris
"person2.SetAge(11);//这里应该编译不过去啊,因为SetAge接收的是*Person类型,而person2是Person类型":
`If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()`
"person3.SetAge2(11);//这里应该编译不过去啊,因为SetAge接收的是Person类型啊,person3是*Person类型":
`A method call x.m() is valid if the method set of (the type of) x contains m`
`The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).`
https://golang.google.cn/ref/spec#Calls
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
https://golang.google.cn/ref/spec#Method_sets
A type may have a method set associated with it.
The method set of an interface type is its interface.
The method set of any other type T consists of all methods declared with receiver type T.
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
https://golang.google.cn/doc/effective_go.html#pointers_vs_values
There is a handy exception, though. When the value is addressable, the language takes care of the common case of invoking a pointer method on a value by inserting the address operator automatically. In our example, the variable b is addressable, so we can call its Write method with just b.Write. The compiler will rewrite that to (&b).Write for us.
#4
更多评论
并不是这一段有疑问;
有疑问的地方在:SetAge和SetAge2 按照方法的定义,SetAge 压栈时一部压入 *Person类型,而SetAge2 压栈时必须压入Person类型,
在上面代码person2.SetAge(11)和person3.SetAge2(11)编译或者运行时应该报错,我认为应该报错的原因正如注释缩写;
然而结果却没有,然后就可是迷惑了.
#2