206

Are maps passed by value or reference in Go ?

It is always possible to define a function as following, but is this an overkill ?

func foo(dat *map[string]interface{}) {...}

Same question for return value. Should I return a pointer to the map, or return the map as value ?

The intention is of course to avoid unnecessary data copy.

1
  • 12
    Everything in Go is passed by value. Some values happen to be pointers, or structures that contain pointers. (you may want a *map in some cases, if you need to reassign the map value at an address) Commented Nov 18, 2016 at 16:06

3 Answers 3

164

In this thread you will find your answer :

Golang: Accessing a map using its reference

You don't need to use a pointer with a map.

Map types are reference types, like pointers or slices[1]

If you needed to change the Session you could use a pointer:

map[string]*Session

https://blog.golang.org/go-maps-in-action

Sign up to request clarification or add additional context in comments.

3 Comments

To avoid any pitfals, be aware that maps are only passed by reference once initialized, and when re-initialized inside a function, the original reference will not be updated. Here is a illustrative playground example: play.golang.org/p/Q6vrAmmJWR6 Or a full article by Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Wrong - maps always get passed the same regardless of whether nil or not. Also a map cannot be reinitialized without passing a pointer to it and using a dereferencing assignment. The same linked code proves the latter and the former is easily proven by not initializing the map. Go is easy to get wrong as the 19 upvotes show.
Personally I think it is misleading to mention (in passing) that "slices are reference types", as they're not really are they? If you pass a slice by value to a function and then append to it multiple times, the caller's copy of that slice is not guaranteed to be updated - instead the called function needs to pass back a new value of the slice. This is because if the slice re-allocates, you get a new value for the slice (hence a = append(a, v) rather than just append(a, v)) Maps do not have this semantic, once a map is created it can be updated without ever yielding a new map value.
60

Here are some parts from If a map isn’t a reference variable, what is it? by Dave Cheney:

A map value is a pointer to a runtime.hmap structure.

and conclusion:

Conclusion

Maps, like channels, but unlike slices, are just pointers to runtime types. As you saw above, a map is just a pointer to a runtime.hmap structure.

Maps have the same pointer semantics as any other pointer value in a Go program. There is no magic save the rewriting of map syntax by the compiler into calls to functions in runtime/hmap.go.

And an interesting bit about history/explanation of map syntax:

If maps are pointers, shouldn’t they be *map[key]value?

It’s a good question that if maps are pointer values, why does the expression make(map[int]int) return a value with the type map[int]int. Shouldn’t it return a *map[int]int? Ian Taylor answered this recently in a golang-nuts thread1.

In the very early days what we call maps now were written as pointers, so you wrote *map[int]int. We moved away from that when we realized that no one ever wrote map without writing *map.

Arguably renaming the type from *map[int]int to map[int]int, while confusing because the type does not look like a pointer, was less confusing than a pointer shaped value which cannot be dereferenced.

Comments

17

No. Maps are reference by default.

    package main

    import "fmt"

    func mapToAnotherFunction(m map[string]int) {
        m["hello"] = 3
        m["world"] = 4
        m["new_word"] = 5
    }

    // func mapToAnotherFunctionAsRef(m *map[string]int) {
    // m["hello"] = 30
    // m["world"] = 40
    // m["2ndFunction"] = 5
    // }

    func main() {
        m := make(map[string]int)
        m["hello"] = 1
        m["world"] = 2

        // Initial State
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        fmt.Println("-----------------------")

        mapToAnotherFunction(m)
        // After Passing to the function as a pointer
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        // Try Un Commenting This Line
        fmt.Println("-----------------------")

        // mapToAnotherFunctionAsRef(&m)
        // // After Passing to the function as a pointer
        // for key, val := range m {
        //  fmt.Println(key, "=>", val)
        // }

        // Outputs
        // hello => 1
        // world => 2
        // -----------------------
        // hello => 3
        // world => 4
        // new_word => 5
        // -----------------------

    }

From Golang Blog-

Map types are reference types, like pointers or slices, and so the value of m above is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function:

// Ex of make function
m = make(map[string]int)

Code Snippet Link Play with it.

4 Comments

They are not reference types (though they are indirect types). If you assign to a map value, you will break its relationship with other variables. Go has no reference types, everything is a value. You can demonstrate this with func mapToAnotherFunction(m map[string]int) { m = nil }, it doesn't empty the map, just overwrites its value in a local way.
Isn't your first comment // After Passing to the function as a pointer incorrect?
@Wug Quoting a post from the official go blog, "Map types are reference types, like pointers or slices"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.