Type assertion to an embedded type from interface{} - go

I want to use type assertion from interface{} to a type I sure the content of the interface{} has embedded reference of. https://play.golang.org/p/G8YrS7WZyQU
package main
import "fmt"
type S1 struct {}
type S2 struct {*S1}
func main() {
s := interface{}(&S2{&S1{}})
// I do not know the s type, but know that it is of `struct {*S1}`
_, ok := s.(*S1)
fmt.Println(ok)
}
Is it even possible in Go?

No, you can't do this. The spec says that you can only type-assert an interface to a type that is identical to the type of the value that was stored in the interface. It also says "A defined type is always different from any other type". Structurally compatible isn't good enough; the only type you can use in your assertion is S2.
Reflection would be possible (see that the value has a Kind of Struct, and has a Field which is a Pointer which has an Elem with a Type that equals reflect.TypeOf(S1{})), at which point an assertion to S1 would succeed on that elem's Interface (but not an assertion to the embedding type).

Related

Go type definition and initialize a pointer [duplicate]

I am using custom types and I have a problem when pointers are involved like below.
Code below is valid:
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) deck {
return cards
}
Code below is valid too:
package main
func str(n []string) *[]string {
return &n
}
The below code instead is not valid. Why so? I have to write a type conversion like return (*deck)(&cards)
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) *deck {
return &cards // compiles with return (*deck)(&cards)
}
The rules about assignments (including returns) are defined in the Go specs: Assignability. The one that is relevant to your case is:
V and T have identical underlying types and at least one of V or T is not a named type.
And Underlying types:
If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself.
The first example compiles because []string is an unnamed type literal with underlying type []string (itself) and deck is a named type with underlying type []string (by your type definition).
The second example does not compile because both *[]string and *deck are unnamed type literals with themselves as (different) underlying types.
To make the second example compile, you can't rely on a direct assignment, but, as you found out, use an explicit type conversion
return (*deck)(&cards)
And this conversion is valid due to the following rule:
ignoring struct tags (see below), x's type and T are pointer types that are not named types, and their pointer base types are not type parameters but have identical underlying types.

Go assignment involving pointers to custom types

I am using custom types and I have a problem when pointers are involved like below.
Code below is valid:
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) deck {
return cards
}
Code below is valid too:
package main
func str(n []string) *[]string {
return &n
}
The below code instead is not valid. Why so? I have to write a type conversion like return (*deck)(&cards)
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) *deck {
return &cards // compiles with return (*deck)(&cards)
}
The rules about assignments (including returns) are defined in the Go specs: Assignability. The one that is relevant to your case is:
V and T have identical underlying types and at least one of V or T is not a named type.
And Underlying types:
If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself.
The first example compiles because []string is an unnamed type literal with underlying type []string (itself) and deck is a named type with underlying type []string (by your type definition).
The second example does not compile because both *[]string and *deck are unnamed type literals with themselves as (different) underlying types.
To make the second example compile, you can't rely on a direct assignment, but, as you found out, use an explicit type conversion
return (*deck)(&cards)
And this conversion is valid due to the following rule:
ignoring struct tags (see below), x's type and T are pointer types that are not named types, and their pointer base types are not type parameters but have identical underlying types.

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?

How can I return a subtype of the specified return value (in this case interface{})?

I have an interface that defines one parameter to have type func(interface{}, proto.Message) interface{} and I'm trying to pass something of type func reduceMsg(a interface{}, b proto.Message) []*PersistentData to it. This results in the following compiler error:
Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}
What is the reason for this error, and how can I work around it? It seems like returning a more specific type than interface{} should be legal. Here's a simple complete example that illustrates the issue:
package main
import "fmt"
func main() {
var t func() interface{} = func() []string { return []string{} }
fmt.Println(t)
}
The type of the object is the whole function signature. If the signature don't match, then it's not the same type and can't be assigned that way.
Anything can be assigned to the empty interface, because all types satisfy the interface, but in your problem neither type is the empty interface, you just have a function that returns an empty interface.
Not because a part of the function can be assigned to another it makes it the same. The type is the whole function signature. I think it's the same logic behind not being able to assign an int to an int8. You can cast them if you want, but for go, they are separate types and you need to deal with making the necessary conversions to be able to assign them.
What you can do is change your second function signature to return an empty interface like this:
func(interface{}, proto.Message) interface{}
func reduceMsg(a interface{}, b proto.Message) interface{} {
var a []*PersistentData
// do something here
return a
}
This way the function signature is the same, so it's consider the same type and you are returning an []*PersistentData. Of course you will need to do a type assertion before using it as such because the program will treat it as an {}interface because that is the type that the function returned.
Referencing the spec,
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Any typed value may be assigned to the blank identifier.
If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.
Assignability
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
In general, Go doesn't allow you to implicitly convert values from one type to another, with the exception of being able to use concrete-typed objects as though they were interfaces (that they implement).
In this particular case, since your function doesn't actually return an interface{}, the compiler would have to do some extra work to wrap up the return value as an interface{} and return it; if you really want to accomplish what you're trying you can do this explicitly yourself:
type Foo struct {
X int
}
func create(x int) Foo {
return Foo{X: x}
}
func main() {
var f func(int) interface{} = func(x int) interface{} {
return create(x)
}
}
which is basically doing (explicitly) the wrapping operation that you want the runtime to do implicitly.

usage of interface{} on a struct to check if it satisfies an interface in golang

Given the following code:
package main
import (
"fmt"
)
type work interface {
filter() bool
}
type organ struct {
name string
}
func (s *organ) filter () bool {
return true;
}
func main() {
kidney := &organ {
name : "kidney",
}
_, ok := interface{}(kidney).(work)
fmt.Println(ok);
}
I did not fully get the following part:
_, ok := interface{}(kidney).(work)
It seems to me, it is converting struct to the interface{} type, which I understand, but why is it required to convert to an interface{} type to check if it satisfies another interface. More specifically, why the following code fails?
ok := kidney.(work)
with error
invalid type assertion: kidney.(work) (non-interface type *organ on left)
TL;DR If you always know the concrete type (e.g., kidney), then you don't need a type assertion; just pass it into your work variable and carry on--the compiler will guarantee that kidney satisfies the work interface, otherwise your program won't compile.
The reason you must first convert the concrete type into an interface{} is because type assertions (i.e., dynamic type checks) only make sense between dynamic types (i.e., interfaces). It doesn't make sense to do a runtime type check on a thing the compiler can guarantee at compile time. Hopefully this makes sense?

Resources