方法与函数的区别

定义
type Animal struct {Name string}//方法是需要绑定的,区别于函数func (a Animal) test() {a.Name="cat"fmt.Println(a.Name)//cat}func main() {a:=&Animal{}a.Name="dog"//这里也是值拷贝,在调用test方法时,会将a作为实参传过去,方法里对a的属性进行更改,这里的不会变a.test() // 编译后实际为 (*a).test(),a作为实参传过去fmt.Println(a.Name)//dog}
类型为指针型
通常为了提升程序效率,对于方法的类型传递一般定义为指针型
type Animal struct {Name string}//方法是需要绑定的,区别于函数func (a *Animal) test() {//(*a).Name="cat",严格写法a.Name="cat"//精简写法fmt.Println(a.Name)}func main() {a:=Animal{}a.Name="dog"a.test()//编译后实际为:(&a).test(),传过去的是指针fmt.Println(a.Name)//cat,传递的是指针,所以a的Name属性发生了变化}
String()方法
如果一个类型实现了String方法,那么在打印时,会自动调用这个方法
type Animal struct {Name string}func (a *Animal) String() string{return fmt.Sprintf("name=%v",a.Name)}func main() {a:=Animal{}a.Name="dog"fmt.Println(&a)//注意这里不能用精简写法//总结:单纯输出不能用精简写法,在.属性或.方法时,才可用}
自定义类型都可以绑定方法
type Int int64func (i Int) print() {fmt.Println("i=",i)//100}func (i *Int) change(n int64) {*i=*i+Int(n)fmt.Println("i=",*i)//101}func main() {var i Int = 100i.print()i.change(1)}
invalid memory address or nil pointer dereference
例子一
package mainimport "fmt"type AAA1 struct {C string}type AAA2 struct {C string}func (*AAA2) eat() {fmt.Println("---------")}type AAA struct {A1 AAA1A2 *AAA2}func main() {a := new(AAA)fmt.Printf("%+v\n", a.A1) // {C:}fmt.Println(a.A2) // nil,地址是0x0,还没分配内存a.A2.eat() // -------- 由于定义的是指针类型的AAA2,所以当AAA中A2为nil// 时,eat方法还能正常访问fmt.Println(a.A1.C) // ""fmt.Println(a.A2.C) // panic,invalid memory address or nil pointer dereference}
例子二
package mainimport "fmt"type AAA struct {}func (AAA) eat() {fmt.Println("---------------------")}type AAA1 struct {}func (*AAA1) eat() {fmt.Println("+++++++++++++++++++++")}func main() {var a *AAAa.eat() // panic,eat方法前定义的是AAA结构体类型,这里会取*a取调用,a是一个nil,那么*a报错var a1 = new(AAA)a1.eat() // --------------------- 正常var a2 *AAA1a2.eat() // +++++++++++++++++++++ 正常}
