Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go type assertion conversion

Tags:

go

I can convert an int to a float64 like this:

var a int = 10
var b float64 = float64(a)

With regards to type assertions, Effective Go states: 'The type must either be the concrete type held by the interface, or a second interface type that the value can be converted to.'

With that in mind, why does the following fail:

func foo(a interface{}) {
    fmt.Println(a.(float64))
}

func main() {
    var a int = 10
    foo(a)
}

This causes a panic: interface conversion: interface is int, not float64.

Note that the Go Spec says:

'For an expression x of interface type and a type T, the primary expression

x.(T)

asserts that x is not nil and that the value stored in x is of type T.'

Which does contradict the Effective Go statement but seems more in line with what I see.

like image 995
Ferguzz Avatar asked May 30 '13 13:05

Ferguzz


People also ask

Does Go support type conversion?

Type conversion happens when we assign the value of one data type to another. Statically typed languages like C/C++, Java, provide the support for Implicit Type Conversion but Golang is different, as it doesn't support the Automatic Type Conversion or Implicit Type Conversion even if the data types are compatible.

What assertion does perform a type conversion and compare two value?

A type assertion brings out the concrete type underlying the interface, while type conversions change the way you can use a variable between two concrete types that have the same data structure.

How does type assertion work in Golang?

A type assertion provides access to an interface value's underlying concrete value. This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t . If i does not hold a T , the statement will trigger a panic.

What is interface {} Golang?

interface{} means you can put value of any type, including your own custom type. All types in Go satisfy an empty interface ( interface{} is an empty interface). In your example, Msg field can have value of any type.


2 Answers

This sentence in Effective Go seems indeed to be confusing. It looks like the author was thinking about structs at that time.

The chapter on assertions in the specification is much clearer :

For an expression x of interface type and a type T, the primary expression

x.(T) asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

More precisely, if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T. In this case, T must implement the (interface) type of x; otherwise the type assertion is invalid since it is not possible for x to store a value of type T. If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.

The fact you can convert your int to a float (and the reverse) doesn't at all mean you can assert they're the same type.

like image 177
Denys Séguret Avatar answered Oct 16 '22 14:10

Denys Séguret


The type must either be the concrete type held by the interface, or a second interface type that the value can be converted to

This basically explains the following:

package main

import "fmt"

type Stringer interface {
    String()
}

type Byter interface {
    Bytes()
}

type Stringbyter interface {
    Stringer
    Byter
}

type Polymorphic float64

func (p *Polymorphic) String() {}

func (p *Polymorphic) Bytes() {}

func main() {
    i := interface{}(new(Polymorphic))
    if _, ok := i.(Stringer); ok {
        fmt.Println("i can be asserted to Stringer")
    }
    if _, ok := i.(Byter); ok {
        fmt.Println("i can be asserted to Byter")
    }
    if _, ok := i.(Stringbyter); ok {
        fmt.Println("i can be asserted to Stringbyter")
    }
    if _, ok := i.(*Polymorphic); ok {
        fmt.Println("i can be asserted to *Polymorphic")
    }
    if _, ok := i.(int); ok {
        fmt.Println("i can be asserted to int") // Never runs
    }
}

The assertion to int fails because it's a concrete type (as opposed to interface type) which is not *Polymorphic itself.

like image 45
thwd Avatar answered Oct 16 '22 16:10

thwd