-2

In go, the value of a map is the zero value when the key does not exist. I have a brief code snippet below: playground

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
}

What's the difference between mm[1] and m above? I used reflect to check, but cannot see the difference between them. Any clue about what cause the difference?

Marc
  • 19,394
  • 6
  • 47
  • 51
  • 2
    Related: [Cannot take the address of map element](https://stackoverflow.com/questions/57321933/cannot-take-the-address-of-map-element/57322003#57322003) – icza Jul 27 '20 at 07:01
  • "In golang, the value of a map is empty value when the key has not been set." Wrong. There are no "empty" values. The value returned is the _zero_ value. – Volker Jul 27 '20 at 07:02
  • @Volker the problem is not about whether "empty" value or "zero" value – Felix Septem Jul 29 '20 at 06:47
  • @Septem I know. Calling it empty is wrong nevertheless. – Volker Jul 29 '20 at 08:57
  • @Volker forgive my poor English, I'm not a native speaker anyway. – Felix Septem Jul 29 '20 at 09:00
  • @Septem This is not a language issue: The term "the zero value" is a _technical_ term defined by the Go Language Spec. – Volker Jul 29 '20 at 11:58
  • @Volker As I have said above, I'm not a native speaker, and I can tell the difference between "zero value" and "empty value".All I make mistake is use a wrong word to describe my question.And I also gain two thumb down due to that. I don't understand a wrong word or a wrong description will cause so treatment, I don't think it's a properly manners for a tech helper. – Felix Septem Jul 30 '20 at 15:30
  • @Septem I doubt the downvotes where due to the wrong technical term. Basic language fundamentals like automatic addressing and map values being unadressable are a) covered in all language introductions and b) are asked three times a week. My comment about "zero" versus "empty" was just to guide you on using the appropriate technical terms. – Volker Jul 31 '20 at 06:24
  • @Volker Thanks for your valuable suggestions. Apologize if I make the duplicate question, but I don't really aware that and not search the useful result due to wrong key word. – Felix Septem Jul 31 '20 at 07:52

1 Answers1

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

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]
Marc
  • 19,394
  • 6
  • 47
  • 51
  • 1
    All correct, but this particular map should be of type `map[int]*sync.Mutex` to begin with, because ["a Mutex must not be copied after first use."](https://golang.org/pkg/sync/#Mutex) – Peter Jul 27 '20 at 12:10