关于go语言编译器自动解引用

关于go语言编译器自动解引用

  • 值类型的实参调用形参为值类型的方法
  • 指针类型的实参调用形参为值类型的方法(会进行“自动解引用”)
  • 值类型的实参调用形参为指针类型的方法(会进行“自动取引用”)
  • 指针类型的实参调用形参为指针类型的方法

我们还是用代码来说明问题。

type node struct {
  Name string
  Next *node
}

// 用c语言翻译,
// void Say(node* n) { printf("%d
", 123); }
func (n *node) Say() {
  fmt.Println(123)
}

// 用c语言翻译,
// void Say(node n) { printf("%d
", 123); }
func (n node) Say2() {
  fmt.Println(2333)
}

func main() {
  n1 := &node{Name: "hui"}
  n1.Say()
  n1.Say2()    // Say2()是值接收器  (*n1).Say2()  go编译器为我们加上*  自动解引用

  n2 := node{Name: "hui"}
  n2.Say()     // Say()是指针接收器 (&n2).Say()  go编译器为我们加上&  自动取引用
  n2.Say2()
}
记住两点
  1. go语言只有值传递,指针也是值传递。

  2. 值类型接收器、指针类型接收器 可以理解为函数 的 一个形参。结合c语言如何做,对于c语言来说传值、传指针哪种会改变实参。

关键理解:当传递给方法的形参是一个值类型时(值类型接收器),原值的内容不会受到影响,因为值传递,传递进来的是原值的复制副本(形参是副本);相反,当方法的形参是一个指针类型时,原值的内容将可能受到影响,因为传递的是指针类型复制,虽然是复制但是指针中存储的地址仍然是实参的真实地址。

一个链表节点删除的例子

以链表节点删除问题为例,由于在go语言中都是参数都是值传递,所以在链表操作的时候不能直接操作形参来修改原来指针的内容,但可以修改其指向的内容为什么呢,用代码来解释

type node struct {
  Name string
  Next *node
}

func main() {
  n1 := &node{Name: "zgh"}
  n2 := &node{Name: "dev"}
  n3 := &node{Name: "devaaa"}
  n1.Next = n2
  n2.Next = n3
  n3.Next = nil
  ts(n2)

  data := make([]string, 0)
  for n1 != nil {
    data = append(data, n1.Name)
    n1 = n1.Next
  }
  fmt.Println(data)
}

func ts(n *node) {
  // 方式一: out: [hui dev devaaa]  不会删除
  n = n.Next  // 这里的n是一个指针的复制,此操作只会更改形参n指针的指向,不会更改实参的指向,如果想修改实参的指向,只能用方式二

  // 方式二: out: [hui devaaa]
  //*n = *n.Next  // 会更改实参,也就是被复制的指针

  // 方式三: out: [hui asada]
  // 这种方式会更改实参,为什么呢 因为这里go语言的编译器会为你加上*来解引用
  //n.Next= n.Next.Next  // 实际(*n).Next=
  //n.Name = "asada"     // 实际(*n).Name=
}
原文地址:https://www.cnblogs.com/iQXQZX/p/14063795.html