How to convert value type by another value's reflect.Type in Golang - go

How to convert value type by another value's reflect.Type in Golang
maybe like this:
func Scan(value interface{}, b string) error {
converted := value.(reflect.TypeOf(b)) // do as "value.(string)"
return nil
}
How can do this properly in golang?

The only way to get a typed value out of an interface is to use a type assertion, and the syntax is value.(T) where T is a type. There's a good reason for this, because it makes the type of the type assertion expression computable: value.(T) has type T. If instead, you allowed value.(E) where E is some expression that evaluates to a reflect.Type (which I think is the gist of your question), then the compiler has no way to (in general) statically determine the type of value.(E) since it depends on the result of an arbitrary computation.

Related

Object variables are passed into functions as interface types. Will there be implicit conversion [duplicate]

I would like to get the reflect.Kind as a reflect.Interface for a type which implements an interface but where its implementation is based on a primitive type: type id string
An alternative answer for this could be how to get any kind of reflect.Type that returns reflect.Interfaces when calling Kind().
Here is a full example on the Go Playground:
type ID interface {
myid()
}
type id string
func (id) myid() {}
func main() {
id := ID(id("test"))
fmt.Println(id)
fmt.Println(reflect.TypeOf(id))
// How to get the kind to return "reflect.Interface" from the var "id"?
fmt.Println(reflect.TypeOf(id).Kind())
}
reflect.TypeOf() (and reflect.ValueOf()) expects an interface{}. Basically whatever value you pass to reflect.TypeOf(), if it's not already an interface value, it will be wrapped in an interface{} implicitly. If the passed value is already an interface value, then the concrete value stored in it will be passed as a interface{}.
In order to avoid this "repacking", this is one of those rare cases when a pointer to interface makes sense, in fact you can't avoid it here. You have to pass a pointer to the interface value.
So if you pass a pointer to interface, this pointer will be wrapped in an interface{} value. You may use Type.Elem() to get the type descriptor of the "pointed type": that is, the element type of the pointer type, which will be the type descriptor of the interface type you're looking for.
Example:
id := ID(id("test"))
fmt.Println(id)
t := reflect.TypeOf(&id).Elem()
fmt.Println(t)
fmt.Println(t.Kind())
Which outputs (try it on the Go Playground):
test
main.ID
interface
See related question: What is the difference between reflect.ValueOf() and Value.Elem() in go?

Why can't I use an empty interface that holds a concrete type of string as a return value in a function declared to return string?

I am a newcomer of go and recently I am following the instruction of A Tour of Go.
I am reading the chapter on Interface and I am really confused by the concept.
The code is as follows
package main
import "fmt"
func main() {
testTypeAssertion()
}
func testTypeAssertion() string {
var i interface{}="hello"
fmt.Printf("type of i is %T",i)
return i
// return "hello"
}
In this case, it will cause error
# example
./prog.go:12:2: cannot use i (type interface {}) as type string in return argument: need type assertion
But if I comment return i and uncomment return "hello", it goes like this
type of i is string
So why exactly do we need a type assertion here?
What's the type of i exactly?
I believe this question is different from cannot use type interface {} as type person in assignment: need type assertion. Because in that question the poster is trying to assign an empty interface value to a variable that has a concrete self-defined type person. In my question, I am trying to figure out why an interface holding a concrete string value cannot be a return value of a function whose return value type is exactly string.
Thanks to mkopriva's answer in the comment section and bugstop's answer. I will accept that it's caused by the different usage of static type and dynamic type. By the way, Reality's answer is very interesting and really helped me to understand the whole concept!
Think of an interface as a little box that holds a type and a value. The box has methods that map to methods on the value in the box.
The statement fmt.Printf("type of i is %T",i) prints the type in the box, not the type of the box itself. Reflect package trickery is required to print the type of i. but that's outside the scope of this question.
The statement return i does not compile because interface{} is not a string. The box contains a string, but the box is not a string.
We can get the value out of the box using a type assertion: return i.(string). This statement panics if i does not contain a string.
it's an interface value i with a dynamic type string.
It may be useful to read about:
How to determine an interface{} value's "real" type?
Interfaces in Go
The variable i is of type interface{}, and its value is the string "hello". An interface is simply a method-set, and since interface{} has no methods specified, all types satisfy it. Because of this, the assignment i="hello" works.
However, you cannot return an interface{} where a string is required, because string is not the same type as an interface{}. You could have returned a string where an interface{} is required, because a string implements interface{}.

Get the reflect.Kind of a type which is based on a primitive type

I would like to get the reflect.Kind as a reflect.Interface for a type which implements an interface but where its implementation is based on a primitive type: type id string
An alternative answer for this could be how to get any kind of reflect.Type that returns reflect.Interfaces when calling Kind().
Here is a full example on the Go Playground:
type ID interface {
myid()
}
type id string
func (id) myid() {}
func main() {
id := ID(id("test"))
fmt.Println(id)
fmt.Println(reflect.TypeOf(id))
// How to get the kind to return "reflect.Interface" from the var "id"?
fmt.Println(reflect.TypeOf(id).Kind())
}
reflect.TypeOf() (and reflect.ValueOf()) expects an interface{}. Basically whatever value you pass to reflect.TypeOf(), if it's not already an interface value, it will be wrapped in an interface{} implicitly. If the passed value is already an interface value, then the concrete value stored in it will be passed as a interface{}.
In order to avoid this "repacking", this is one of those rare cases when a pointer to interface makes sense, in fact you can't avoid it here. You have to pass a pointer to the interface value.
So if you pass a pointer to interface, this pointer will be wrapped in an interface{} value. You may use Type.Elem() to get the type descriptor of the "pointed type": that is, the element type of the pointer type, which will be the type descriptor of the interface type you're looking for.
Example:
id := ID(id("test"))
fmt.Println(id)
t := reflect.TypeOf(&id).Elem()
fmt.Println(t)
fmt.Println(t.Kind())
Which outputs (try it on the Go Playground):
test
main.ID
interface
See related question: What is the difference between reflect.ValueOf() and Value.Elem() in go?

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.

Go: Named type assertions and conversions

If I have a custom type that simply redefines a pre-defined type with a name:
type Answer string
And I try to use it in a function that accepts the pre-defined type:
func acceptMe(str string) {
fmt.Println(str)
}
func main() {
type Answer string
var ans Answer = "hello"
// cannot use ans (type Answer) as type string in function argument
acceptMe(ans)
// invalid type assertion: ans.(string) (non-interface type Answer on left)
acceptMe(ans.(string))
// Does work, but I don't understand why if the previous doesn't:
acceptMe(string(ans))
}
Why does the type assertion fail, but the conversion work?
Type assertion works for interfaces only. Interface can have arbitrary underlying type, so we have type assertion and type switch to the rescue. Type assertion returns bool as the second return value to indicate if assertion was successful.
Your custom type Answer can have only one underlying type. You already know the exact type - Answer and the underlying type - string. You don't need assertions, since conversion to the underlying type will always be successful.
Old answer:
Just convert your custom type to string. The conversion will succeed since your custom type has string as an underlying type. The conversion syntax: string(ans). Go Play

Resources