为了账号安全,请及时绑定邮箱和手机立即绑定

带有空接口的“通用”代码中的强制类型

带有空接口的“通用”代码中的强制类型

Go
人到中年有点甜 2021-05-07 18:27:25
我正在阅读这本书http://algs4.cs.princeton.edu/home/,我认为将Go中的示例作为学习练习来实现会很好,但是该书使用Java作为其语言来描述。第一章中的一章讨论了设置一些核心数据类型/容器样式类以供以后重用,但是我很难将它们设置为Go设置,这主要是因为这些数据类型似乎喜欢使用Java泛型。例如,我编写了以下代码package bagtype T interface{}type Bag []Tfunc (a *Bag) Add(t T) {    *a = append(*a, t)}func (a *Bag) IsEmpty() bool {    return len(*a) == 0}func (a *Bag) Size() int {    return len(*a)}从某种意义上说,这可以正常工作,我可以将项目添加到中,Bag并检查其大小和所有内容。但这也意味着以下代码是合法的a := make(bag.Bag,0,0)a.Add(1)a.Add("Hello world!")a.Add(5.6)a.Add(time.Now())我只是想知道是否有任何强制类型的方式,使其符合类似于以下内容的合同Bag<T> bagOfMyType = new Bag<T>()例如Bag<Integer> bagOfInts = new Bag<Integer>()我知道Go没有泛型,并且它们并不是真正的The Go Way,但我只是想知道是否有可能在编译时“强制”执行任何操作(可能没有)
查看完整描述

2 回答

?
四季花海

TA贡献1811条经验 获得超5个赞

我是Go我的新手,所以我很好奇是否有人会得到更好的答案,但是我是这样看的:


您希望在编译时强制执行,当在Add()上调用时IntSlice,其参数为int。好吧,这是您的操作方式:


func (i *IntSlice) Add(t int) {

    *i = append(*i, t)

}

由于没有泛型,因此Add()每种类型的方法都会有所不同Bag,因此Bag假设您需要,接口将变为:


type Bag interface {

    IsEmpty() bool

    Size() int

}

这对我来说很有意义,因为您不能Bag绕过一圈,只扔任何东西。Bag仅仅知道某物是一个东西还不足以知道如何调用Add()它。您必须知道Bag您要处理的是哪种类型。


您可以使接口特定于该类型,例如IntBag,但是由于实际上只有一种类型可以满足该接口,因此您也可以删除该接口并将其名称更改IntSlice为IntBag。


基本上,这意味着完全放弃所有类似于泛型的东西,而只是使用一些可以满足您需要的方法来创建类型:


type IntBag []int


func (b *IntBag) Add(i int) {

    *b = append(*b, i)

}


func (b IntBag) IsEmpty() bool {

    return len(b) == 0

}


func (b IntBag) Size() int {

    return len(b)

}

更新:有时泛型确实会派上用场。在我看来,我们只能根据具体情况选择最适合特定问题的方法。使用空接口和反射,您可以得到一些类似泛型的行为,但是它看起来很丑陋,并且您放弃了一些编译时类型检查。或者您放弃泛型而进行一些代码重复。或者您只是用完全不同的方式来做。


几周前,我问了一个问题,关于我应该如何使用Go来处理看起来像我需要类层次结构的问题。答案基本上是没有通用的解决方案。视情况而定。我认为泛型也是如此:Go中没有泛型,也没有将基于泛型的解决方案转换为Go的通用解决方案。

在许多情况下,您可能会在另一种语言中使用泛型,但是在Go中,接口是完全足够的(或真正的亮点)。您的示例在这里,接口并不是真正合适的替代品。


查看完整回答
反对 回复 2021-05-17
  • 2 回答
  • 0 关注
  • 184 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信