【问题标题】:What is the "go" way to checking custom types in go?在 go 中检查自定义类型的“go”方法是什么?
【发布时间】:2014-08-14 06:38:07
【问题描述】:

我试图在 golang 中测试对象的确切类型(服装结构或接口),并试图弄清楚如何做到这一点,不是真正像便宜货黑客。 (请注意,我要问的不是字符串、整数、浮点数、切片等内置类型)。

假设我有一个实现 Speak 方法的 Animal 接口:

type Animal interface {
    Speak() string
}

以及实现该接口的 Dog 结构:

type Dog struct {
}

func (d Dog) Speak() string {
    return "Woof!"
}

假设我有一些变量 x,我如何检查它的结构类型并采取相应措施?

例如,我想要类似的东西:

func isDog(thing Animal{}) bool {
    if reflect.TypeOf(thing) == packageName.Dog{
        return true
    }else{
        return false
    }
}

我想到的唯一解决方案并不是我真正想做的,但我想它有效。首先创建一个我要检查的类型的空结构,然后使用反射包检查是否相等。比如:

func isDog(thing Interface{}) bool {
    d := Dog{}
    if reflect.TypeOf(thing) == reflect.TypeOf(d){
        return true
    }else{
        return false
    }
}

我不太喜欢这样的原因是,假设我有一个更大的代码,我最终需要一个 switch 语句。然后,我必须编写很多我觉得没有必要的额外代码,例如,我需要创建许多空结构类型的数量,因为我有案例。这似乎没有必要而且非常丑陋。这是唯一的方法吗?我还希望它对我来说足够灵活,它也可以检查指针。比如:

func isDog(thing Interface{}) bool {
    d := Dog{}
    if reflect.TypeOf(thing) == packageName.Dog{
        return true
    }else if reflect.TypeOf(thing) == *packageName.Dog{
        return true
    }else{
        return false
    }
}

【问题讨论】:

    标签: types go


    【解决方案1】:

    要确定接口变量的动态类型,可以使用type assertion 的两个返回形式。例如,您的 isDog 函数可以实现为:

    func isDog(thing Animal) bool {
        _, isdog := thing.(packageName.Dog)
        _, isdogptr := thig.(*packageName.Dog)
        return isdog || isdogptr
    }
    

    【讨论】:

    • 看起来确实和我想要的完全一样,但是......当我尝试它时,代码向我抛出了一个我不明白的奇怪错误。它说impossible type assertion "github.com/pinocchio/farm/pkgName".Dog does not implement "github.com/pinocchio/farm/pkgName".Animal (Speak 方法有指针接收器)。奇怪...我不明白,这两个东西定义了完全相同的方法并返回相同的类型,没有错别字。
    • 如果你有func (d *Dog) Speak() string这样的方法,它只会在*Dog的方法集中用于实现接口,而不是Dog。您无法获得指向存储在接口变量中的值的指针,因此无法使用该方法。
    • @JamesHenstridge 令我困惑的是,它为什么会崩溃?如果它不能转换为那种类型,为什么不直接说而不是给我一个错误?
    • 如果您有一个d 类型为Dog 的变量并调用d.Speak(),则调用会自动转换为(&d).Speak(),因为该方法将指针作为其接收者。问题是您不能将指针指向存储在接口变量中的值,因此该方法不被视为Dog 的方法集的一部分。由于这意味着Dog 没有实现Animal 接口,因此类型断言永远不会通过,因此编译器会将其视为错误。
    【解决方案2】:

    惯用的方法是使用type switch,而不是直接键入断言。

    func isDog(animal Animal) bool {
        switch animal.(type) {
        case Dog:
        case *Dog:
        default:
            return false
        }
        return true
    }
    

    【讨论】:

    • 我认为在这种情况下滥用空白标识符和myVariable || randomIdent 很严重。
    猜你喜欢
    • 2018-03-10
    • 1970-01-01
    • 2016-07-17
    • 2016-06-19
    • 2011-01-07
    • 1970-01-01
    • 2014-01-12
    • 2016-01-30
    • 2021-07-12
    相关资源
    最近更新 更多