我正在努力学习 Go。
我在 go 中发现了 Set 的简洁实现:gopkg.in/fatih/set.v0,但我更喜欢用更明确的名称来命名我的集合,
set.Set
,做类似的事情:
type View set.Set
本质上,我希望我的
View
类型继承 set.Set
的方法。因为,View
是描述符的 set.Set
。但我知道 Go 在继承和一般打字方面非常出色。
目前我一直在尝试以下kinda继承,但在尝试使用某些函数(如
func Union(set1, set2 Interface, sets ...Interface) Interface
或func (s *Set) Merge(t Interface)
)时会导致大量错误:
type View struct {
set.Set
}
我想知道是否有一种方法可以以类似于 Go 的方式实现我想要的目标,或者我只是想将我的优秀 OO 实践应用到一种抛弃它们的语言中。
如果其他人回到这个问题,从 Go 1.9 开始支持类型别名。
类型别名的形式为:
type T1 = T2
因此,在您的示例中,您只需执行
type View = set.Set
即可,一切都会按照您的意愿进行。
注意,我认为您最初提出的简单别名在语法上是有效的,尽管快速查看了集合库,而不是别名
set.Set
,它可能对别名set.Interface
更有意义,例如:
package main
import (
"fmt"
set "gopkg.in/fatih/set.v0"
)
// View is a type alias for the set.Interface interface
type View set.Interface
// Display takes one of our View types in order to print it.
func Display(view View) {
fmt.Println(view.List())
}
func main() {
// create our first set.Interface or View
v1 := set.New()
v1.Add("foo")
// create our second set.Interface or View
v2 := set.New("bar")
// call a set function
v3 := set.Union(v1, v2)
// call our function that takes a View
Display(v3)
}
您可能已经注意到我在某种程度上作弊,因为除了定义
Display
函数的参数之外,我在上面的代码中没有真正提到别名类型,您会注意到上面的参数是在 View
实例中而不是比 set.Interface
。如果您有很多函数在处理这些事情,那么对于您的领域来说,这可能会更具表现力。
请注意,因为我们的
View
类型是接口类型的别名,所以它阻止将您自己的函数添加到该类型,因为 Go 不允许我们为函数拥有接口接收器类型(我可能表达错误) 。我的意思是你不能做这样的事情:
func (v View) Display() string {
return v.String()
}
总而言之,我认为别名很好,它可以使内部 API 更具可读性,并且您可以依靠编译器来帮助消除某些类型的错误;但是,这不允许您向自定义类型添加功能。如果需要,则需要采用替代方法,嵌入或简单组合(即
View
具有 Set
)。
与 2016 年相比,您很快就会拥有(Go 1.24,2025 年第一季度),Spec 46477:“泛型:允许别名上的类型参数”,在 issue 68778 中实现,如
GOEXPERIMENT=aliastypeparams=1
。
在您的情况下(创建一个类型
View
,它是一组描述符),类型参数化别名将允许您为由一个或多个类型参数化的类型创建别名。
这意味着您将能够为
set.Set
创建一个类型参数化别名,它采用描述符类型的类型参数,然后使用此别名来定义 View
类型。
type Set[T any] set.Set[T]
type View Set[descriptor]