一、基本介绍
在某些情况下,我们需要定义方法。比如 Person 结构体,除了有一些字段外(姓名、年龄...),还可以有一些行为动作(吃、唱歌...),这就需要用方法才能实现。
Go中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是 struct 有。
示例:
type Person struct { Name string } // 给Person类型绑定一个方法 func (person Person) Eat() { fmt.Printf("%s正在吃东西...", person.Name) } func main() { person := Person{"pd"} person.Eat() // 调用方法 }
对上面代码总结:
- Eat 方法和 Person 类型绑定;
- Eat 方法只能通过 Person 类型的(变量 / 实例 / 对象)来调用,而不能直接调用,也不能使用其他类型的实例来调用;
- func (person Person) Eat() {},person表示哪个Person的实例调用,可以理解为 java 中的 this,python 中的 self;
- 方法的参数、返回值与函数一样。
二、方法的引用传递与值传递
结构体是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝的传递方式。如果想在方法中,修改结构体字段的值,可以通过结构体指针的方式来处理。
type Person struct { Name string Age int } func (p *Person) Change() { /* 因为 p 是指针,所以标准的访问字段的方式是 (*p).Name,但写成 p.Name 也是可以的,因为编译器在底层会帮我们处理,方便程序员 使用。 同理,在下面的 main 函数中,本因 (&p).Change() 这样调用方法, 但写成 p.Change() 也是可以的。 */ p.Name = "乔治" p.Age = 20 } func (p Person) Change1() { p.Name = "诺手" p.Age = 22 } func main() { p := Person{"佩奇", 10} fmt.Println(p.Name, p.Age) // 佩奇 10 p.Change() fmt.Println(p.Name, p.Age) // 乔治 20 p1 := Person{"德玛", 11} p1.Change1() fmt.Println(p1.Name, p1.Age) // 德玛 11 (&p1).Change1() // 同理,编译器会优化,因为 Change1() 中的Person不是一个指针 fmt.Println(p1.Name, p1.Age) // 德玛 11 }
结论:不管结构体实例是 p.Change() 还是 (&p).Change() 的形式调用方法,都是由方法中 p 对应的结构体是 *Person 还是 Person 决定的!!!,*Person就是引用传递,Person就是值传递。