方法与函数的区别

image.png

定义

  1. type Animal struct {
  2. Name string
  3. }
  4. //方法是需要绑定的,区别于函数
  5. func (a Animal) test() {
  6. a.Name="cat"
  7. fmt.Println(a.Name)//cat
  8. }
  9. func main() {
  10. a:=&Animal{}
  11. a.Name="dog"
  12. //这里也是值拷贝,在调用test方法时,会将a作为实参传过去,方法里对a的属性进行更改,这里的不会变
  13. a.test() // 编译后实际为 (*a).test(),a作为实参传过去
  14. fmt.Println(a.Name)//dog
  15. }

类型为指针型

通常为了提升程序效率,对于方法的类型传递一般定义为指针型

  1. type Animal struct {
  2. Name string
  3. }
  4. //方法是需要绑定的,区别于函数
  5. func (a *Animal) test() {
  6. //(*a).Name="cat",严格写法
  7. a.Name="cat"//精简写法
  8. fmt.Println(a.Name)
  9. }
  10. func main() {
  11. a:=Animal{}
  12. a.Name="dog"
  13. a.test()//编译后实际为:(&a).test(),传过去的是指针
  14. fmt.Println(a.Name)//cat,传递的是指针,所以a的Name属性发生了变化
  15. }

String()方法

如果一个类型实现了String方法,那么在打印时,会自动调用这个方法

  1. type Animal struct {
  2. Name string
  3. }
  4. func (a *Animal) String() string{
  5. return fmt.Sprintf("name=%v",a.Name)
  6. }
  7. func main() {
  8. a:=Animal{}
  9. a.Name="dog"
  10. fmt.Println(&a)//注意这里不能用精简写法
  11. //总结:单纯输出不能用精简写法,在.属性或.方法时,才可用
  12. }

自定义类型都可以绑定方法

  1. type Int int64
  2. func (i Int) print() {
  3. fmt.Println("i=",i)//100
  4. }
  5. func (i *Int) change(n int64) {
  6. *i=*i+Int(n)
  7. fmt.Println("i=",*i)//101
  8. }
  9. func main() {
  10. var i Int = 100
  11. i.print()
  12. i.change(1)
  13. }

invalid memory address or nil pointer dereference

例子一

  1. package main
  2. import "fmt"
  3. type AAA1 struct {
  4. C string
  5. }
  6. type AAA2 struct {
  7. C string
  8. }
  9. func (*AAA2) eat() {
  10. fmt.Println("---------")
  11. }
  12. type AAA struct {
  13. A1 AAA1
  14. A2 *AAA2
  15. }
  16. func main() {
  17. a := new(AAA)
  18. fmt.Printf("%+v\n", a.A1) // {C:}
  19. fmt.Println(a.A2) // nil,地址是0x0,还没分配内存
  20. a.A2.eat() // -------- 由于定义的是指针类型的AAA2,所以当AAA中A2为nil
  21. // 时,eat方法还能正常访问
  22. fmt.Println(a.A1.C) // ""
  23. fmt.Println(a.A2.C) // panic,invalid memory address or nil pointer dereference
  24. }

例子二

  1. package main
  2. import "fmt"
  3. type AAA struct {
  4. }
  5. func (AAA) eat() {
  6. fmt.Println("---------------------")
  7. }
  8. type AAA1 struct {
  9. }
  10. func (*AAA1) eat() {
  11. fmt.Println("+++++++++++++++++++++")
  12. }
  13. func main() {
  14. var a *AAA
  15. a.eat() // panic,eat方法前定义的是AAA结构体类型,这里会取*a取调用,a是一个nil,那么*a报错
  16. var a1 = new(AAA)
  17. a1.eat() // --------------------- 正常
  18. var a2 *AAA1
  19. a2.eat() // +++++++++++++++++++++ 正常
  20. }