go map value 和 nil 之间的区别

Fel*_*tem -2 go

在 go 中,当 key 不存在时,map 的值是零值。我在下面有一个简短的代码片段: 操场

package main

import (
    "sync"
)

func main() {
    var mm map[int]sync.Mutex
    var m sync.Mutex
    mm[1].Lock() // not work due to cannot call pointer method on mm[1] and cannot take the address of mm[1]
    m.Lock() // work normal
}
Run Code Online (Sandbox Code Playgroud)

mm[1]m上面有什么区别?我用reflect来检查,但看不出它们之间的区别。关于导致差异的任何线索?

Mar*_*arc 7

The issue is not about the zero value of a map, it's about addressability during methods calls.

The Lock method on a mutex has a pointer receiver:

func (*Mutex) Lock
Run Code Online (Sandbox Code Playgroud)

Given the variable m sync.Mutex, calling a method on it with a pointer receiver will automatically turn into &m.Lock(), per the spec:

A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()

The important part of this is the addressable requirement. The variable m is addressable, but the returned value of a map lookup is not. This means that the compiler will not attempt to call &mm[1].Lock().

These can be seen in the error messages returned when you attempt to compile your example:

./prog.go:11:7: cannot call pointer method on mm[1]
./prog.go:11:7: cannot take the address of mm[1]
Run Code Online (Sandbox Code Playgroud)