bjnsn
bjnsn

Reputation: 2820

Why is value changing after function execution?

I'm currently teaching myself Go, and I'm having trouble understanding a certain behavior:

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 is executed twice. The initial time, during the Increment call, it prints size: 1 but after Increment has returned it prints size: 0. Why are those values different?

Upvotes: 1

Views: 85

Answers (2)

Himanshu
Himanshu

Reputation: 12675

The reason your nodes are not added to the original linkedList because you are not using pointer to the struct. So even if the Increment function in your example code changes the value. The copy of the struct is changed not the actual struct.

You can declare methods with pointer receivers. This means the receiver type has the literal syntax *T for some type T. (Also, T cannot itself be a pointer such as *int.)

If you want to change the linkedlistNode struct counter to show the nodes added to the list you should be using a pointer type receiver on both methdos working to modify the linked list as:

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

And Inside the main pass an address to the linkedList to use those pointer type receivers as:

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

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

Working Code Go playground

Note:-

There are two reasons to use a pointer receiver.

  • To modify the value that its receiver points to.
  • To avoid copying the value on each method call. This can be more efficient if the receiver is a large struct

For more information go through Method Sets

Upvotes: 1

Emin Laletovic
Emin Laletovic

Reputation: 4324

With Increment and LogState defined the way you've defined them, you are working only with the copy of the value of List. This means that if you make some changes inside Increment function, they are visible only inside Increment's function scope and only for the remainder of that particular scope's existence. To confirm you are always working with a copy of of the initial List value, you can log &list before executing Increment function and &l inside the same function.

If you want to make changes permanent, you should work with a pointer to a memory address. That means your your function should be defined like this:

func (l *List) Increment()

func (l *List) LogState()

This way, you are passing a memory reference (pointer to an address in memory) and every time you change a value of l, you are changing it on the passed memory reference and it reflects everywhere.

Upvotes: 1

Related Questions