There aren’t many places where Go syntax is ambiguous, but here’s one:
Conversions
…
If the type starts with the operator
*
or<-
, or if the type starts with the keywordfunc
and has no result list, it must be parenthesized when necessary to avoid ambiguity:*Point(p) // same as *(Point(p)) (*Point)(p) // p is converted to *Point <-chan int(c) // same as <-(chan int(c)) (<-chan int)(c) // c is converted to <-chan int func()(x) // function signature func() x (func())(x) // x is converted to func() (func() int)(x) // x is converted to func() int func() int(x) // x is converted to func() int (unambiguous)
Of these three ambiguous cases, *
is the one you’re most likely to run into, so let’s look at an example.
Let’s imagine we have two types that are identical, except for their struct tags. This might happen if you want to use one for marshaling JSON, and the other for unmarshaling:
// User is when the user sets their password.
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
// UserDisplay supresses the password for display purposes.
type UserDisplay struct {
Username string `json:"username"`
Password string `json:"-"`
}
Now let’s further imagine we have a *User
value that we want to convert to a *UserDisplay
value. This can be done with a simple conversion between struct types, since struct tags are ignored (as we’ll see shortly). But to convert from a pointer of one struct to a pointer of another, we need to use the *
operator, which introduces ambiguity:
u := &User{Username: "bob", Password: "abracadabra"}
ud := *UserDisplay(u) // cannot convert u (variable of type *User) to type UserDisplay
So let’s try the prescribed solution instead:
u := &User{Username: "bob", Password: "abracadabra"}
ud := (*UserDisplay)(u)
j, _ := json.Marshal(ud)
fmt.Println(string(j)) // Prints: {"username":"bob"}
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)