如何确保自定义数据结构中的编译时安全

我正在编写一些数据结构来让我的脚弄湿并学习 Go 语言,并且正在为 Go 缺乏泛型而苦苦挣扎。


在我的实现中,我选择强制每个用户实现一个接口,以便我的结构可以抽象地引用这些对象,但我不喜欢我的解决方案,因为正如您将看到的那样,这在编译时没有得到验证。


比较器接口

保存在容器中的每个对象都必须实现Compare以下签名的函数(如果您只想保存原始类型,则很麻烦)


type Comparer interface {

    Compare(Comparer) int

}

然后,您可以拥有实现接口的各种元素,例如float64或自定义结构:


浮动64

type number float64


func (n1 number) Compare(comparer Comparer) int {

    n2, _ := comparer.(number)

    if n1 > n2 {

        return 1

    } else if n1 < n2 {

        return -1

    } else {

        return 0

    }

}

type Person struct {

    Age int

}


func (p1 Person) Compare(comparer Comparer) int {

    p2, _ := comparer.(Person)

    if p1.Age > p2.Age {

        return 1

    } else if p1.Age < p2.Age {

        return -1

    } else {

        return 0

    }

}

现在我可以比较其中的一些东西:


func main() {

    fmt.Println(number(2).Compare(number(4)))    // -1

    fmt.Println(Person{26}.Compare(Person{28}))  // -1

    fmt.Println(Person{26}.Compare(number(28)))  //  1

}

这里的问题是我不应该比较 aPerson和 a number。我意识到我可以在运行时检查类型,但我想找到 a) 一种验证类型的编译时方法或 b) 一种不同的方法来通用地实现数据结构。


问题


我知道使用内置数据结构几乎可以做任何可能需要的事情……但是如果没有泛型或运行时类型检查,人们如何制作自己的数据结构呢?

由于 Go 中的接口实现似乎使用了鸭子类型,那么 Go 在编译时如何强制类型?


catspeake
浏览 169回答 1
1回答

白板的微信

我的意思是该代码没有任何不安全的地方......只是没有编译时安全。例如,在您下面的方法中,第一行对 进行类型断言comparer,如果它不是数字并且您没有_LHS 上的第二项,那么它将返回一个错误,您可以采取相应的行动。或者你可以在没有它的情况下调用它,并且panic会发生将它留给调用者来处理它(这很合适,因为他们是用错误的参数调用方法的人,就像InvalidOperationException在 C# 中得到一个一样)。func (n1 number) Compare(comparer Comparer) int {&nbsp; &nbsp; n2, _ := comparer.(number)&nbsp; &nbsp; if n1 > n2 {&nbsp; &nbsp; &nbsp; &nbsp; return 1&nbsp; &nbsp; } else if n1 < n2 {&nbsp; &nbsp; &nbsp; &nbsp; return -1&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return 0&nbsp; &nbsp; }}这与像 C# 这样的语言之间的区别纯粹在于泛型,它允许您以更高的编译时安全性来执行这些类型的事情(因为您不能错误地调用该方法)。话虽如此,在 C# 有泛型之前有一段时间,而在此之前的许多语言根本没有它们。即使在具有泛型的语言中,这些操作也不会比您经常进行的转换更不安全。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go