---
title: "Go scope"
createdAt: "2018-05-21T21:20:00.000Z"
updatedAt: "2018-05-21T21:20:00.000Z"
tags: ["code","go"]
draft: false
aliases: ["/code/2018/05/21/go-scope.html","/posts/2018-05-21-go-scope"]
atUri: "at://did:plc:mracrip6qu3vw46nbewg44sm/site.standard.document/3mhnqy7amt72h"
readingTime: false
---

Scoping in Go is built around the notion of code blocks. You can find several good explanations of how variable scoping work in Go on Google. I'd like to highlight one slightly unintuitive consequence of Go's block scoping if you're used to a language like Python, keeping in mind, this example does not break with Go's notion of block scoping:

Let's start with a common pattern in Python:

```python
class Data(object):

    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return('Data({})'.format(self.val))

li = [Data(2), Data(3), Data(5)]

print(li)

for d in li:
    d.val += 1

print(li)

```

Output:

```sh
[Data(2), Data(3), Data(5)]
[Data(3), Data(4), Data(6)]
```

Here, we mutate `val` on each of the `Data` classes in the list and show our result at the end of the loop, confirming that each `val` was incremented. However, in Go, a similiar looking construction actually produces a different result:

```go
package main

import "fmt"

func main() {
    type Data struct {
        val int
    }
    l := []Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }
    fmt.Printf("%+v\n", l)
    for _, d := range l {
        d.val += 1
    }
    fmt.Printf("%+v\n", l)
}
```

<https://play.golang.org/p/O6vT7s8Qiym>

Output:

```sh
[{val:2} {val:3} {val:5}]
[{val:2} {val:3} {val:5}]
```

So why does this happen? Block scoping.

Let's look at simple example of block scoping:

```go
package main

import "fmt"

func main() {
    x := 1
    fmt.Println(x)
    if true {
        x := 2
        fmt.Println(x)
    }
    fmt.Println(x)
}
```

<https://play.golang.org/p/1ebX4Oy92d0>

Output:

```sh
1
2
1
```

The value of `x` changes after being assigned in the `if` statement code block, but is discarded after exiting the block.

We see the same behavior inside a `for` loop:

```go
package main

import "fmt"

func main() {
    x := "main"
    fmt.Println(x)
    for i := 0; i < 1; i++ {
        x := "for"
        fmt.Println(x)
    }
    fmt.Println(x)
}
```

<https://play.golang.org/p/bOH2ObC5vS1>

Output:

```sh
main
for
main
```

You can even create a code block with bare curly braces:

```go
package main

import "fmt"

func main() {
    x := "main"
    fmt.Println(x)
    {
        x := "for"
        fmt.Println(x)
    }
    fmt.Println(x)
}
```

<https://play.golang.org/p/N1TWR29F12n>

Output:

```sh
main
for
main
```

Now let's return to our original example:

```go
package main

import "fmt"

func main() {
    type Data struct {
        val int
    }
    l := []Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }
    fmt.Printf("%+v\n", l)
    for _, d := range l {
        d.val += 1
    }
    fmt.Printf("%+v\n", l)
}
```

<https://play.golang.org/p/O6vT7s8Qiym>

The loop variable `d` is in the block scope of the `for` loop. As we saw above, anything you do to a variable scoped to a block ceases to exist outside the block. So how can we actually change the value of the `val` field on the structs in the slice? We can't use the loop variable, since it's a value scoped to inside our loop.

Let's try and get access the structs directly inside our loop. We're actually not too far off:

```go
package main

import "fmt"

func main() {
    type Data struct {
        val int
    }
    l := []Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }
    fmt.Printf("%+v\n", l)
    for i, _ := range l {
        l[i].val += 1
    }
    fmt.Printf("%+v\n", l)
}
```

<https://play.golang.org/p/uo4ntARc0HG>

Output:

```sh
[{val:2} {val:3} {val:5}]
[{val:3} {val:4} {val:6}]
```

Cool. It looks like we got the result we were looking for. But why does our first example work in Python? Python actually is hiding the use of values and pointers/references whereas Go requires us to handle them explictly. Using pointers in Go, we can construct a loop that behaves similarly to our Python example:

```go
package main

import "fmt"

type Data struct {
    val int
}

func main() {

    l := []*Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }

    prettyPrint(l)

    for _, d := range l {
        d.val += 1
    }

    prettyPrint(l)

}

func prettyPrint(l []*Data) {
    out := "["
    for i, d := range l {
        out += fmt.Sprintf("%+v", d)
        if i != len(l)-1 {
            out += " "
        }
    }
    out += "]"
    fmt.Println(out)
}
```

<https://play.golang.org/p/bX6zbswFc3w>

Output:

```sh
[&{val:2} &{val:3} &{val:5}]
[&{val:3} &{val:4} &{val:6}]
```

Note: we are now using a slice of `*Data` rather than a slice of `Data`. This example works similarly to the one in Python. Even though `d` is a variable scoped to the `for` loop, its value is a pointer that points to the same memory location as the pointers in `l` respectively. We can validate that in the following manner:

```go
package main

import "fmt"

type Data struct {
    val int
}

func main() {

    l := []*Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }

    for i, d := range l {
        fmt.Println("variable addresses")
        println(&d)
        println(&l[i])
        fmt.Println("pointer addresses")
        println(d)
        println(l[i])
        break
    }
}
```

<https://play.golang.org/p/q6l8cdllQy1>

Output:

```sh
variable addresses
0x1042ff84
0x1042ff9c
pointer addresses
0x1042ff80
0x1042ff80
```

We see that the memory locations of the variables `d` and `l[i]` are different, but that they both point to the same memory location -- the same struct in `l`.

You may wonder how in our earlier example we managed to mutate values in the slice without explicitly using pointers or references. We sidestepped these issues by using the slice `l` rather than a variable scoped to the `for` loop. The value of `l[i]` (where `i` is some index) is the same inside and outside the loop and references the same struct in memory. Here's proof:

```go
package main

func main() {
    type Data struct {
        val int
    }
    l := []Data{
        {val: 2},
        {val: 3},
        {val: 5},
    }
    println(&l[0])
    for i, _ := range l {
        println(&l[i])
        l[i].val += 1
        break
    }
}
```

<https://play.golang.org/p/cIgaloLhcvQ>

Output:

```sh
0x1042ff9c
0x1042ff9c
```

Note: To see a variable's memory address `println(&...)` can be substituted with `fmt.Println(unsafe.Pointer(&...))`

Hope you enjoyed!