I am trying to understand the representation of a reflection value:
type S struct {
F string `species:"gopher" color:"blue"`
}
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("v = ", v) // v = 3.4
s := S{}
ss := reflect.ValueOf(s)
fmt.Println("ss = ", ss) // ss = {}
I understand that the representation of a reflection interface value is a two-word pair that gives a pointer to type information and a pointer to the associated value.
What is the reflection representation of a variable. Is it just the value and if so, how is the type determined by code below:
fmt.Println("type:", reflect.TypeOf(x))
If the representation is just value, as it appears to be, where does the code above find the type information?
The type of reflect.TypeOf is:
func TypeOf(i interface{}) Type
When you call reflect.ValueOf(x) in your code, the value of x is implicitly converted to interface{}. At compile time, the type of x is known (float64), and the interface value is represented as you already know; as a two word pair with the pointer to the information for float64 and a pointer to the float64 value (3.4).
The same reasoning applies to s later in your program.
There's very little implicit conversion done between types in Go, but the conversion between values and interfaces when calling a function (or assigning to a variable) is an exception.
Related
I want to iterate over struct definition recursively and for slices get a type of a singular element. Then, create an empty instance of that type. For example:
type Path struct {
Name string
Points []Coordinate
}
type Coordinate struct {
Latitude float64
Longitude float64
}
Assuming that types are unknown at runtime, how can I create an empty instance of the nested type (in the above example Coordinate). I mean:
x := Coordinate{}
When at input I get Path (which can be any other struct, with slices of different types)?
If you have the reflect.Type descriptor of some value, you may use reflect.New() function to obtain a pointer to a new, zeroed value.
This will return you a reflect.Value value. This will be a pointer, to get the reflect.Value of the pointed object, use Value.Elem(). To "unwrap" the value held inside reflect.Value(), you may use Value.Interface().
So if you have a reflect.Type descriptor of a slice, you may use Type.Elem() to get the reflect.Type descriptor of the element type of the slice.
See this example:
p := Path{
Name: "foo",
Points: []Coordinate{
{1.1, 2.2},
{3.3, 4.4},
},
}
v := reflect.ValueOf(p)
f := v.FieldByName("Points")
cv := reflect.New(f.Type().Elem()).Elem()
c := cv.Interface()
fmt.Printf("%#v\n", c)
This outputs (try it on the Go Playground):
main.Coordinate{Latitude:0, Longitude:0}
When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.
Question is:
Why does RuneFunc and StringMap work, but not Integer?
https://play.golang.org/p/buKNkrg5y-
package main
type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string
func main() {
//m := make(StringMap)
//mf(m)
var i Integer = 5
nf(i)
//var f func(rune) rune
//ff(f)
}
func mf(i map[string]string) {
}
func ff(i func(rune)rune) {
}
func nf(i int) {
}
Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.
Integer and int
int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.
If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:
var i Integer = 5
nf(int(i))
What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:
nf(5)
Try these on the Go Playground.
The reason for this is in the Spec: Assignability:
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
[...]
x is an untyped constant representable by a value of type T.
5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).
If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.
See related question: Golang: Creating a Constant Type and Restricting the Type's Values
RuneFunc and func(rune) rune
The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.
And there's an assignability rule which allows this:
x's type V and T have identical underlying types and at least one of V or T is not a named type.
So in this case:
var f RuneFunc
ff(f)
f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.
Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg
I am pulling in some data from a db - and I have a pointer to a float32 - because if I use a pointer - then I am able to check if it is nil (which it quite often might be).
When it is not nil, I want to get the value - how do I dereference it so I can get the actual float32? I can't actually find a link for that anywhere! I know exactly what I want to do, and I just can't find the syntax in Go, which I am still very new to - all help appreciated.
I know how to dereference the pointer if it is a straight float32...
but if I have the following struct...
type MyAwesomeType struct{
Value *float32
}
Then after I do :
if myAwesomeType.Value == nil{
// Handle the error later, I don't care about this yet...
} else{
/* What do I do here? Normally if it were a straight float32
* pointer, you might just do &ptr or whatever, but I am so
* confused about how to get this out of my struct...
*/
}
The Go Programming Language Specification
Address operators
For an operand x of pointer type *T, the pointer indirection *x
denotes the variable of type T pointed to by x. If x is nil, an
attempt to evaluate *x will cause a run-time panic.
Use the * operator. For example,
package main
import "fmt"
type MyAwesomeType struct {
Value *float32
}
func main() {
pi := float32(3.14159)
myAwesomeType := MyAwesomeType{Value: &pi}
if myAwesomeType.Value == nil {
// Handle the error
} else {
value := *myAwesomeType.Value
fmt.Println(value)
}
}
Playground: https://play.golang.org/p/8URumKoVl_t
Output:
3.14159
Since you are new to Go, take A Tour of Go. The tour explains many things, including pointers.
Pointers
Go has pointers. A pointer holds the memory address of a value.
The type *T is a pointer to a T value. Its zero value is nil.
var p *int
The & operator generates a pointer to its operand.
i := 42
p = &i
The * operator denotes the pointer's underlying value.
fmt.Println(*p) // read i through the pointer p
*p = 21 // set i through the pointer p
This is known as "dereferencing" or "indirecting".
Unlike C, Go has no pointer arithmetic.
When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.
Question is:
Why does RuneFunc and StringMap work, but not Integer?
https://play.golang.org/p/buKNkrg5y-
package main
type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string
func main() {
//m := make(StringMap)
//mf(m)
var i Integer = 5
nf(i)
//var f func(rune) rune
//ff(f)
}
func mf(i map[string]string) {
}
func ff(i func(rune)rune) {
}
func nf(i int) {
}
Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.
Integer and int
int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.
If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:
var i Integer = 5
nf(int(i))
What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:
nf(5)
Try these on the Go Playground.
The reason for this is in the Spec: Assignability:
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
[...]
x is an untyped constant representable by a value of type T.
5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).
If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.
See related question: Golang: Creating a Constant Type and Restricting the Type's Values
RuneFunc and func(rune) rune
The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.
And there's an assignability rule which allows this:
x's type V and T have identical underlying types and at least one of V or T is not a named type.
So in this case:
var f RuneFunc
ff(f)
f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.
Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg
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.