dopatraman
dopatraman

Reputation: 13908

Switch case on interface type

I'm trying to identify a type that implements an interface using a switch:

package main    

import "fmt"


type Abser interface {
    Abs() float64
}

type Vertex struct {
    X, Y int
}

func (v *Vertex) Abs() float64 {
    return float64(v.X)
}

func do(i interface{}) {
    switch v := i.(type) {
    case Abser:
        fmt.Println("theres an Abser")
    case Vertex:
        fmt.Println("theres a Vertex")
    default:
        fmt.Printf("I don't know about type %T!\n", v)
    }
}

func main() {
    do(Vertex{1,2})
}

This code outputs the value for Vertex instead of Abser. Ideally it should have output theres an Abser since Vertex implements the Abs() method. Is it possible to use a switch-case to do this?

Upvotes: 4

Views: 7318

Answers (2)

leaf bebop
leaf bebop

Reputation: 8232

It is not about the switch command, but about pointer receivers.

If you change func (v *Vertex) Abs() float64 to func (v Vertex) Abs() float64, it will give the output theres an Abser.

In general code, a type can use its pointer method - you can call Vertex{1,2}.Abs(), but what happened behind it is that the Go compiler rewrites it as (&Vertex{1,2}).Abs() for you. So Vertex does not implement Abser.

But on the contrary, a pointer type has all the methods its underlying type has. So even if the API is defined as func (v Vertex) Abs() float64, &Vertex{1,2} is still an Abser. See: https://play.golang.org/p/ONnsjApMywO

See Also:

Method set: https://golang.org/ref/spec#Method_sets

Upvotes: 4

superfell
superfell

Reputation: 19040

The problem is that Vertex isn't an Abser, only *Vertex is, if you change your Abs() impl to

func (v Vertex) Abs() float64 {
    return float64(v.X)
}

then Vertex itself is an Abser and your code will print theres an Abser

Upvotes: 1

Related Questions