Why first example fails, but second goes well?
What is correct way to do such assertion?
example 1 https://play.golang.org/p/4LRGQLdGPB
// example 1
type Packet map[string]interface{}
func get(pack interface{}) {
if packet, ok := pack.(Packet); !ok {
fmt.Printf("error: %#v, %#v
", pack, packet)
}
}
func main() {
pack := make(map[string]interface{})
pack["qwe"] = 123
get(pack)
}
// error: map[string]interface {}{"qwe":123}, main.Packet(nil)
example 2 https://play.golang.org/p/Pd9jvvNrq5
// example 2
type Packet map[string]interface{}
func get(pack interface{}) {
var p Packet
if packet, ok := pack.(map[string]interface{}); !ok {
fmt.Printf("%#v, %#v
", pack, packet)
} else {
p = packet
}
fmt.Printf("%#v
", p)
}
func main() {
pack := make(map[string]interface{})
pack["qwe"] = 123
get(pack)
}
// main.Packet{"qwe":123}
The problem is you're not passing a Packet
, you're passing a map[string]interface{}
, which is a completely different type as far as Go is concerned.
If you use pack := make(Packet)
or pack := Packet{}
, it will work as intended.
The answers and comments so far are misunderstanding, mixing up, or at least brushing over a lot of detail in the difference between a type assertion and a type conversion.
The syntax thing.(AType)
is a type assertion. It will be evaluated at runtime. The criteria for when this will be successful (i.e. ok == true
) can be boiled down to really 2 situations:
thing
is literally of type AType
. Not a redeclared type like your Packet
.AType
is an interface and thing
satisfies the interface.In all other cases, ok
will be false
(or if you use the single value version foo := bar.(Baz)
, foo
will be whatever the appropriate zero value is).
The syntax AType(thing)
is a type conversion. It will be evaluated at compile time. A type conversion requires the in memory structure of AType
and whatever type thing
is, to be identical.
Therefore, in your example the type assertion, packet, ok := pack.(Packet)
results in ok == false
because Packet
is a non-interface type, and packet
is not literally of that type, it is of type map[string]interface
.
However, you can do the type conversion Packet(pack)
, because the type Packet
and the variable pack
have the same underlying memory structure, map[string]interface{}