| 
                            
                                  方法方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。在调用方法的时候,值类型既可以调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。
 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package main import "fmt" type Person struct {     age int } func (p Person) AddAge() {     p.age += 1 }   func (p *Person) GetAge() {     p.age += 1 }   func main() {     // p1 是值类型     p := Person{age: 18}     // 值类型 调用接收者也是值类型的方法     p.AddAge()     fmt.Println(p.age)       // ----------------------       // p2 是指针类型  指针类型调用接收者是值类型的方法     p2 := &Person{age: 100}     p2.AddAge()     fmt.Println(p2.age)     //值类型 调用接收者也是指针类型的方法     p3 := Person{age: 18}     p3.GetAge()     fmt.Println(p3.age)     // 指针类型 调用收者也是指针类型的方法     p4 := Person{age: 100}     p4.GetAge()     fmt.Println(p4.age) } //18 //100 //19 //101 |  
	
		
			| 值接收者 | 指针接收者 |  
			| 值类型调用者 | 传递一个副本 | 使用值的引用来调用方法 |  
			| 指针类型调用者 | 传递一个副本 | 方法里的操作会影响到调用者,类似于指针传参,拷贝了一份指针 |  总结:1.一个结构体的方法的接收者可能是类型值或指针
 2.当接受者不是一个指针时,该方法操作对应接受者的值的副本,即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。
 3.如果接收者是指针,则调用者修改的是指针指向的值本身。
 接口实现当结构体实现一个接口时,可以在方法中设置一个接收者,比如对于以下接口: 
	
		
			| 1 2 3 | type Inter interface {     foo() } |  结构体在实现它时,方法的接收者类型可以是:值、指针。比如: 
	
		
			| 1 2 3 4 | type S struct {}   func (s S) foo() {} // 值类型 func (s *S) foo() {} // 或者指针类型 |  在使用结构体初始化接口变量时,结构体的类型也可以是:值、指针。比如: 
	
		
			| 1 2 3 4 5 6 | //赋值 var s Inter = S{} // 值类型 s.foo()   var s Inter = &S{} // 指针类型 s.foo() |  那么调用接口方法的组合实际有四种情况:值类型结构体 -> 赋值给接口 -> 调用接收者类型为值类型的结构体方法
 指针类型结构体 -> 赋值给接口 -> 调用接收者类型为指针类型的结构体方法
 值类型结构体 -> 赋值给接口 -> 调用接收者类型为指针类型的结构体方法(不通过)
 指针类型结构体 -> 赋值给接口 -> 调用接收者类型为值类型的结构体方法
 结构体类型为值类型、调用了接收者为指针的方法不通过。但是反过来,结构体为指针类型时,却可以调用接收值为值或指针的任何方法。这是为什么呢?
 接收者是方法的一个额外的参数,而 Go 在调用函数的时候,参数都是值传递的。将一个指针拷贝,它们还是指向同一个地址,指向一个确定的结构体;将一个值拷贝,它们变成了两个不同的结构体,有着不同的地址。这会导致以下两种情况: 当在一个结构体指针上,通过接口,调用一个接收者为值类型的方法时,Go 首先会创建这个指针的副本,然后将这个指针解引用,再作为接收者参数传递给该方法。这两个指针指向相同的地址,所以它们传递给方法的接收者参数都是相同的。 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | type Inter interface {     foo() } type S struct {} func (s S) foo() {} // 接收者为值类型的方法   var a Inter = &S{} // 使用结构体指针初始化一个接口 a.foo() // 调用 foo 方法   // 实际上底层是这样的: // 首先拷贝 a 的底层值,即 `&S{}`,是一个结构体指针: var b *S = a.inner_value // a、b 是不同的变量,但是指向同一个结构体 // 然后将 b 解引用,传递给 foo: foo(*b) // *b 和 *(a.inner_value) 其实都表示同一个结构体 |  这些规则用来说明是否我们一个类型的值或者指针实现了该接口: 
	类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集类型 T 的可调用方法集包含接受者为 T 的所有方法 两者分别在何时使用如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;如果方法的接收者是指针类型,则调用者修改的是指针指向的对象本身。 使用指针作为方法的接收者的理由: 
	方法能够修改接收者指向的值。避免在每次调用方法时复制该值,在值的类型为大型结构体时,这样做会更加高效。是使用值接收者还是指针接收者,不是由该方法是否修改了调用者(也就是接收者)来决定,而是应该基于该类型的本质。 
 |