如果接口变量的类型是别名

时间:2016-08-25 22:14:48

标签: go types interface

Golang新手在这里。

这个问题的简短版本是:给定一个可能是别名类型的接口值,检查它是否属于基础类型的正确方法是什么?

我发现类型断言和类型切换不起作用。

例如,在以下程序中,我从基础类型Alias<N>中获得了一堆自动生成的命名类型Origin。我有一个接口变量v,它可以是任何类型。如果Field类型为v,我想使用其Origin值。

package main

import (
    "fmt"
)

type Origin struct {
    Field int
}

type Alias1 Origin
type Alias2 Origin
type Alias3 Origin

// A bunch of other aliases

func f(v interface{}) {
    if _, ok := v.(Origin); ok {
        fmt.Println("type assertion works")
    }

    switch v := v.(type) {
    case Origin:
        fmt.Println("type switch works")
    case Alias1:
        fmt.Printf("No... Alias1 Value: %v\n", v.Field)
    case Alias2:
        fmt.Printf("No... Alias2 Value: %v\n", v.Field)
    default:
        fmt.Printf("No... Alias3 Value: %T\n", v.(Origin).Field)
    }
}

func main() {
    f(Alias1{Field: 10})
    f(Alias2{Field: 10})
    f(Alias3{Field: 10})
}

输出如https://play.golang.org/p/3WjpX6NcfF

所示
No... Alias1 Value: 10
No... Alias2 Value: 10
panic: interface conversion: interface is main.Alias3, not main.Origin

什么是正确的方法? (我无法在Origin中列出f的所有别名类型,因为这些别名类型会自动生成并分散在各处。)任何帮助都非常受欢迎。提前谢谢!

=====编辑1 =====

尝试使用reflect包,但仍然没有解决方案:https://play.golang.org/p/3LtG9ZOkQd

package main

import (
    "fmt"
    "reflect"
)

type Origin struct {
    Field int
}

type Alias1 Origin

// A bunch of other aliases

func g(v interface{}) {
    vt := reflect.TypeOf(v)
    ot := reflect.TypeOf(Origin{})
    if vt.ConvertibleTo(ot) {
        fmt.Printf("%T is convertible to Origin", v)

        // panic: interface is main.Alias3, not main.Origin
        // fmt.Printf("Value: %v\n", v.(Origin).Field)

        // error: vt is not a type
        // fmt.Printf("Value: %v\n", v.(vt).Field)

        // error: cannot convert v (type interface {}) to type Origin: need type assertion
        // fmt.Printf("Value: %v\n", Origin(v).Field)

    }
}

func main() {
    g(Alias1{Field: 10})
}

1 个答案:

答案 0 :(得分:1)

我能得到的最短的是:

fmt.Printf("Value: %v\n", reflect.ValueOf(v).Convert(ot).Interface().(Origin).Field)

(而不是代码中的第三个fmt)

使用反射将v转换为原点类型。但后来使用类型断言,但这将是反映。值。要将其强制转换为Origin类型,需要将其转换为interface {},然后将其类型声明为Origin类型。