what is the different between (&t).value and t.value in golang? t is a struct - go

I have such a struct in golang like below:
type test struct {
value int
}
and when I tried this
t := test{1}
fmt.Println((&t).value)
fmt.Println(t.value)
the compiler did not report an error,and I got the same output of 1,
this output confused me.What is different between (&t).value and t.value in golang?

The selector expression p.f where p is a pointer to some struct type and f is a field of that struct type is shorthand for (*p).f.
Your expression (&t) results in a value of the pointer type *test. So that makes (&t).value the shorthand for (*(&t)).value.
Selectors:
The following rules apply to selectors:
For a value x of type T or *T where T is not a pointer
or interface type, x.f denotes the field or method at the
shallowest depth in T where there is such an f. If there is not
exactly one f with shallowest depth, the selector expression is
illegal.
For a value x of type I where I is an interface type,
x.f denotes the actual method with name f of the dynamic value
of x. If there is no method with name f in the method set of
I, the selector expression is illegal.
As an exception, if the type of x is a defined pointer type
and (*x).f is a valid selector expression denoting a field (but
not a method), x.f is shorthand for (*x).f.
In all other cases, x.f is illegal.
If x is of pointer type and has the value nil and x.f
denotes a struct field, assigning to or evaluating x.f causes a
run-time panic.
If x is of interface type and has the value nil, calling or
evaluating the method x.f causes a run-time panic.

Related

Weird Behavior of String() Method on Embedded Types in Go

I'm not able to understand how the String() method works for embedded structs in Go. Consider this:
type Engineer struct {
Person
TaxPayer
Specialization string
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("name: %s, age: %d", p.Name, p.Age)
}
type TaxPayer struct {
TaxBracket int
}
func (t TaxPayer) String() string {
return fmt.Sprintf("%d", t.TaxBracket)
}
func main() {
engineer := Engineer{
Person: Person{
Name: "John Doe",
Age: 35,
},
TaxPayer: TaxPayer{3},
Specialization: "Construction",
}
fmt.Println(engineer)
}
The output of this code is {name: John Doe, age: 35 3 Construction}. But if I remove the Person.String() method definition then the output is just 3 (it calls engineer.TaxPayer.String()). However if I remove TaxPayer.String() method definition as well, then the output is {{John Doe 35} {3} Construction}. I initially thought there must be an implicit String() method defined for the overall Engineer struct, but there is no such method.
Why is method invocation behaving this way? If I instead have the methods for each embedded type named anything other than String() (say Foo()), and then try to do fmt.Println(engineer.Foo()), I get an (expected) compilation error: ambiguous selector engineer.Foo. Why is this error not raised when the methods' name is String() instead?
If you embed types in a struct, the fields and methods of the embedded type get promoted to the embedder type. They "act" as if they were defined on the embedder type.
What does this mean? If type A embeds type B, and type B has a method String(), you can call String() on type A (the receiver will still be B, this is not inheritance nor virtual method).
So far so good. But what if type A embeds type B and type C, both having a String() method? Then A.String() would be ambiguous, therefore in this case the String() method won't be promoted.
This explains what you experience. Printing Engineer will have the default formatting (struct fields) because there would be 2 String() methods, so none is used for Engineer itself. Of course the default formatting involves printing the fields, and to produce the default string representation of a value, the fmt package checks if the value being printed implements fmt.Stringer, and if so, its String() method is called.
If you remove Person.String(), then there is only a single String() method promoted, from TaxPlayer, so that is called by the fmt package to produce the string representation of the Engineer value itself.
Same goes if you remove TaxPayer.String() : then Person.String() will be the only String() method promoted, so that is used for an Engineer value itself.
This is detailed in Spec: Struct types:
A field or method f of an embedded field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.
[...] Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
The first sentence states "if x.f is a legal selector". What does legal mean?
Spec: Selectors:
For a primary expression x that is not a package name, the selector expression
x.f
denotes the field or method f of the value x.
[...] A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T. The number of embedded fields traversed to reach f is called its depth in T. The depth of a field or method f declared in T is zero. The depth of a field or method f declared in an embedded field A in T is the depth of f in A plus one.
The following rules apply to selectors:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
[...]
The essence is emphasized, and it explains why none of the String() methods are called in the first place: Engineer.String() could come from 2 "sources": Person.String and TaxPayer.String, therefore Engineer.String is an illegal selector and thus none of the String() methods will be part of the method set of Engineer.
Using an illegal selector raises a compile time error (such as "ambiguous selector engineer.Foo"). So you get the error because you explicitly tried to refer to engineer.Foo. But just embedding 2 types both having String(), it's not a compile-time error. The embedding itself is not an error. The use of an illegal selector would be the error. If you'd write engineer.String(), that would again raise a compile time error. But if you just pass engineer for printing: fmt.Println(engineer), there is no illegal selector here, you don't refer to engineer.String(). It's allowed. (Of course since method set of Engineer does not have a promoted String() method, it won't be called to produce string representation for an Engineer–only when printing the fields.)

When a receiver method T cannot take *T?

The official Go site writes as follows:
As the Go specification says, the method set of a type T consists of
all methods with receiver type T, while that of the corresponding
pointer type *T consists of all methods with receiver *T or T. That
means the method set of *T includes that of T, but not the reverse.
This distinction arises because if an interface value contains a
pointer *T, a method call can obtain a value by dereferencing the
pointer, but if an interface value contains a value T, there is no
safe way for a method call to obtain a pointer. (Doing so would allow
a method to modify the contents of the value inside the interface,
which is not permitted by the language specification.)
Even in cases where the compiler could take the address of a value to
pass to the method, if the method modifies the value the changes will
be lost in the caller.
My question is, when can't the compiler take a value to a pointer receiver value?
Addressable is defined in the https://golang.org/ref/spec#Address_operators:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
A counter examples include map values and functions:
func f() {}
func main() {
var m map[string]string
p1 := &m["foo"] // cannot take the address of m["foo"]
p2 := &f // cannot take the address of f
}

Selector of pointer for method from base type in go

It's obvious that the following code will work fine:
package main
import "fmt"
type T struct {
a int
}
func (t T) M() {
fmt.Println("M method")
}
func main() {
var t = &T{1}
t.M() // it's interesting
}
But as I can see from specification:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
But in example M is not from *T, it's from T. I know that *T includes method set of T but as I can see specification doesn't tell us about method set of *T. Do I understand the specification wrong or correctness of the line with comment is based on some other specification rule?
You quoted:
x.f denotes the field or method at the shallowest depth in T
The quote refers to depth. "Definition" of depth is:
A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T. The number of embedded fields traversed to reach f is called its depth in T. The depth of a field or method f declared in T is zero. The depth of a field or method f declared in an embedded field A in T is the depth of f in A plus one.
The key is embedding. Your struct does not embed a single type. So by definition, the depth of your T.M is zero.
Your t variable is of type *T (that is the type of the &T{} expression, which is taking the address of a struct composite literal: it generates a pointer to a unique variable initialized with the literal's value).
And quoting from Spec: Method values:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
t.M is a reference to the non-interface method T.M, and since t is a pointer, it will be automatically dereferenced: (*t).M().
Now let's see an example where the "at the shallowest depth" does matter.
type T struct{}
func (t T) M() { fmt.Println("T.M()") }
type T2 struct {
T // Embed T
}
func (t T2) M() { fmt.Println("T2.M()") }
func main() {
var t T = T{}
var t2 T2 = T2{T: t}
t2.M()
}
In main() we call t2.M(). Since T2 embeds T, this could refer to T2.T.M and T2.M. But since depth of T2.T.M is one and depth of T2.M is zero, T2.M being at the shallowest depth in T2, therefore t2.M will denote T2.M and not T2.T.M, so the above example prints (try it on the Go Playground):
T2.M()
From Method Sets:
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).

What is the difference between type conversion and type assertion?

What is the main differences between :
v = t.(aType) // type assertion
v = aType(t) // type conversion
Where should I use type assertion or type conversion ?
A type assertion asserts that t (an interface type) actually is a aType and t will be an aType; namely the one wrapped in the t interface. E.g. if you know that your var reader io.Reader actually is a *bytes.Buffer you can do var br *bytes.Buffer = reader.(*bytes.Buffer).
A type conversion converts one (non-interface) type to another, e.g. a var x uint8 to and int64 like var id int64 = int64(x).
Rule of thumb: If you have to wrap your concrete type into an interface and want your concrete type back, use a type assertion (or type switch). If you need to convert one concrete type to an other, use a type conversion.
tl;dr x.(T) asserts that the dynamic value of interface x is T at run time; T(x) converts the type of an expression x to some other type.
Type Assertion
You know that in Go an interface is basically a method set specification, and you can assign to an interface variable any value whose type implements that method set1.
The type assertion written x.(T) asserts that the value stored in the interface x is of type T. You use a type assertion when you want to unbox that value.
One of the most common uses is when you have interface{} and you need to retrieve the concrete value it stores. A typical example, Context values:
func foo(ctx context.Context) {
s := ctx.Value("my_key").(string) // signature is `Value(key interface{}) interface{}`
// do something with s...
}
It is called assertion because at compile time it is not known whether x actually holds the concrete type T, but you assert that it does. That's why the unchecked assertion y := x.(T) panics if x doesn't actually hold a T — you must use the comma-ok assignment v, ok := x.(T) to avoid it.
ctx = context.WithValue(ctx, "my_key", "foo")
s := ctx.Value("my_key").(int) // panic
v, ok := ctx.Value("my_key").(string)
fmt.Println(v, ok) // "foo" true
In addition, when T in x.(T) is an interface itself, the assertion checks that the value stored in x implements T. The outcome is the same as above.
Type Conversion
A type conversion written as T(x) instead "changes the type of an expression to the type specified by the conversion", i.e. changes the type of x to T. An important property of conversions is that they are statically checked2. An invalid conversion simply won't compile:
type Foo string
type Bar int
a := "foo"
fmt.Println(Bar(a)) // cannot convert a (type string) to type Bar
The main condition for a conversion to be valid is assignability between the types involved, but there's several more, including conversions between numerical types, strings and byte/rune slices, directed channels, slices and array pointers, etc.
In simple terms, you use a conversion when you already know what are the types involved, and simply want to change one to the other:
b := []byte("foo") // converts string literal to byte slice
Notes:
1: more formally, when the value's method set is a superset of the interface method set; this is also why the empty interface interface{} can hold any value, because any set is a superset of an empty set.
2: type assertions are also checked at compile time when the type T in x.(T) does not implement the interface. In practice, this won't help you catch errors when x is interface{} since all types implement it.

If S contains an anonymous field T, does the method sets of S include promoted methods with receiver *T?

The title of the question is almost quoted from the golang specification:
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
This is a go playground shows that The method inc() is promoted.
package main
import (
"fmt"
)
// just an int wrapper
type integer struct {
i int
}
func (self *integer) inc() {
self.i++
}
type counter struct {
integer
}
func main() {
c := counter{}
c.inc()
fmt.Println(c)
}
No the methods of *T would not be promoted. The specification doesn't explicitly allow it so it isn't allowed. However, there is a reason behind this.
At times you may call a *T method on T. However, there is an implicit reference taken. Methods of *T are not considered part of T's method set.
From the calls section of the Go specification:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
From the address operator section of the Go specification:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
If a S contains a *T, you don't even need to take its address so the methods can be called. If *S contains a T, you know T is addressable because T is a field selector of a pointer indirected struct. For S containing T, this cannot be guaranteed.
UPDATE: why does that code work?
Remember that *S contains the method set of *T. Also, as I quoted before:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
Put the two together and you have your answer. Counter is addressable and &counter contains the method set of *T. Therefore, counter.Inc() is shorthand for (&counter).Inc().

Resources