为什么函数执行后值会改变?

时间:2018-10-14 05:55:32

标签: go

我目前正在自学Go,但无法理解某些行为:

package main

import (
    "fmt"
)

type List struct {
    n int
}

func (l List) Increment() {
    l.n += 1
    l.LogState() // size: 1
}

func (l List) LogState() {
    fmt.Printf("size: %v\n", l.n)
}

func main() {
    list := List{}
    list.Increment()

    fmt.Println("----")
    list.LogState() // size: 0
}

https://play.golang.org/p/-O24DiNPkxx

LogState执行两次。初始时间是在Increment调用期间,它打印size: 1,但是在Increment返回之后,它打印size: 0。为什么这些值不同?

2 个答案:

答案 0 :(得分:1)

通过IncrementLogState定义了定义它们的方式,您只能使用值为List副本。这意味着,如果您在Increment函数内部进行了某些更改,则它们仅在Increment的函数范围内可见,并且仅在该特定范围存在的其余部分内可见。为确认您始终使用初始List值的副本,可以在执行&list函数和Increment之前在同一函数中登录&l

如果要使更改永久生效,则应使用指向内存地址的指针。这意味着您的函数应该这样定义:

func (l *List) Increment()

func (l *List) LogState()

这样,您将传递一个内存引用(指向内存中地址的指针),并且每次更改值l时,您都将在传递的内存引用上对其进行更改,并且它会在所有地方反映出来。

答案 1 :(得分:1)

由于未使用指向结构的指针,所以未将节点添加到原始链表的原因。因此,即使示例代码中的Increment函数更改了该值。结构的副本被更改,而不是实际的结构。

  

您可以使用指针接收器声明方法。这意味着   接收器类型的某些类型T的字面语法为* T。(此外,T   本身不能是* int之类的指针。)

如果您想更改linkedlistNode结构计数器以显示添加到列表中的节点,则应该在两个方法上都使用指针类型接收器来将链接列表修改为:

func (l *LinkedList) AddInitialValue(v interface{})
func (l *LinkedList) LogState()

然后在主内部传递一个地址到linkedList,以将那些指针类型的接收器用作:

func main() {
    list :=  &LinkedList{}
    list.AddInitialValue(9)

    fmt.Println("----")
    list.LogState() // size: 0
}

工作代码Go playground

注意:-

使用指针接收器有两个原因。

  
      
  • 修改接收者指向的值。
  •   
  • 为避免在每次方法调用时复制值。如果接收器是大型结构,这会更有效
  •   

有关更多信息,请访问Method Sets