方法与函数的区别
定义
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 int64
func (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 = 100
i.print()
i.change(1)
}
invalid memory address or nil pointer dereference
例子一
package main
import "fmt"
type AAA1 struct {
C string
}
type AAA2 struct {
C string
}
func (*AAA2) eat() {
fmt.Println("---------")
}
type AAA struct {
A1 AAA1
A2 *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 main
import "fmt"
type AAA struct {
}
func (AAA) eat() {
fmt.Println("---------------------")
}
type AAA1 struct {
}
func (*AAA1) eat() {
fmt.Println("+++++++++++++++++++++")
}
func main() {
var a *AAA
a.eat() // panic,eat方法前定义的是AAA结构体类型,这里会取*a取调用,a是一个nil,那么*a报错
var a1 = new(AAA)
a1.eat() // --------------------- 正常
var a2 *AAA1
a2.eat() // +++++++++++++++++++++ 正常
}