在 Go 中如何使用泛型 入门 - 使用具有多种类型的泛型
在 没有泛型的Go集合 和 使用泛型的集合 文章中我们已经初步介绍了泛型,并且举了卡牌的例子。本篇内容我们继续介绍 使用具有多种类型的泛型。文章中的示例,继续沿用之前的示例代码,如果有不清楚的,可以参考前面的文章。
一旦你创建了一个泛型类型,比如你的 Deck,你就可以将它与任何其他类型一起使用。 当你创建通用 Deck 的实例并希望它与 *PlayingCard
类型一起使用时,你唯一需要做的就是在创建值时指定该类型。 要支持不同的类型,你可以将 *PlayingCard
类型替换为你想要使用的新类型。
在本节中,你将创建一个新的 TradingCard 结构体类型来表示不同类型的卡片。 然后,将更新你的程序来创建一副 *TradingCards
。
要创建你的 TradingCard 类型,请再次打开你的 main.go 文件并添加定义:
...
import (
...
)
type TradingCard struct {
CollectableName string
}
func NewTradingCard(collectableName string) *TradingCard {
return &TradingCard{CollectableName: collectableName}
}
func (tc *TradingCard) String() string {
return tc.CollectableName
}
此 TradingCard 类似于我们的 PlayingCard ,但它没有 Suit 和 Rank 字段,而是有一个 CollectableName 字段来跟踪交易卡的名称。 它还包括 NewTradingCard 构造函数和 String 方法,类似于 PlayingCard。
现在,为装满 *TradingCards
的 Deck 创建 NewTradingCardDeck 构造函数:
...
func NewPlayingCardDeck() *Deck[*PlayingCard] {
...
}
func NewTradingCardDeck() *Deck[*TradingCard] {
collectables := []string{"Sammy", "Droplets", "Spaces", "App Platform"}
deck := &Deck[*TradingCard]{}
for _, collectable := range collectables {
deck.AddCard(NewTradingCard(collectable))
}
return deck
}
当创建或返回 *Deck
时,我们已将 *PlayingCard
替换为 *TradingCard
,但这是我们需要对 Deck 进行的唯一更改。 我们有一片特殊的 DigitalOcean 收藏品,然后我们循环将每个 *TradingCard
添加到套牌中。 套牌的 AddCard 方法仍然以相同的方式工作,但这次它接受来自 NewTradingCard 的 *TradingCard
值。 如果你尝试从 NewPlayingCard 传递一个值,编译器会给你一个错误,因为它需要 *TradingCard
,但你提供的是 *PlayingCard
。
最后,更新你的 main 函数,创建一个新的 *TradingCards
牌组,用 RandomCard 随机抽取一张牌,并打印出牌的信息:
...
func main() {
playingDeck := NewPlayingCardDeck()
tradingDeck := NewTradingCardDeck()
fmt.Printf("--- drawing playing card ---\n")
playingCard := playingDeck.RandomCard()
...
fmt.Printf("card rank: %s\n", playingCard.Rank)
fmt.Printf("--- drawing trading card ---\n")
tradingCard := tradingDeck.RandomCard()
fmt.Printf("drew card: %s\n", tradingCard)
fmt.Printf("card collectable name: %s\n", tradingCard.CollectableName)
}
在最后一次更新中,我们使用 NewTradingCardDeck 创建了一个新的集换式卡组并将其存储在 tradingDeck
中。 然后,由于我们仍然使用与以前相同的 Deck 类型,则可以使用 RandomCard 从牌组中随机获取一张交易卡并打印出来。 我们还可以直接在 tradingCard 上引用和打印 CollectableName 字段,因为我们使用的通用 Deck 已将 C 定义为 *TradingCard
。
此更新还显示了使用泛型的价值。 要支持一种全新的卡片类型,您根本不需要更改套牌。 Deck 的类型参数允许您在创建 Deck 实例时提供要使用的卡片类型,从那时起,与该 Deck 值的任何交互都使用 *TradingCard
类型而不是 *PlayingCard
类型。
要查看更新后的代码,请保存更改并使用 go run 再次运行程序:
$ go run main.go
输出结果如下
--- drawing playing card ---
drew card: Q of Diamonds
card suit: Diamonds
card rank: Q
--- drawing trading card ---
drew card: App Platform
card collectable name: App Platform
程序完成后,我们应该看到类似于上面输出的内容,只是使用不同的卡。我们会看到绘制两张卡片:原始纸牌和添加的新交易卡。
在本节中,我们添加了一种新的 TradingCard 类型,以代表与原始 Playcard 不同类型的卡。添加了交易卡类型后,我们将创建 NewTradingCarddeck 构造函数,以创建和填充 Deck 上的交易卡。最后,我们更新了 main 方法,以使用新的交易卡 Deck 并打印有关绘制随机卡的信息。
除了创建新功能 NewTradingCarddeck 外,还可以用不同的卡填充 Deck 外,我们无需对 Deck 进行任何其他更新即可支持全新的卡类型。这是泛型力量。可以编写一次代码并将其重新使用以用于其他多种类型的类似数据。但是,我们当前 Deck 的一个问题是,由于我们拥有 C any
声明,它都可以用于任何类型。这可能是我们想要的东西,因此我们可以使用&Deck [int] {}
创建一个int值的 Deck 。但是,如果我们希望 Deck 仅包含卡片,则需要一种方法来限制允许的数据类型。
相关文章
在 Golang 中使用 If-Else 和 Switch Loop Inside HTML 模板
发布时间:2023/04/27 浏览次数:65 分类:Go
-
本篇文章介绍了在 Golang 的 HTML 模板中使用 if-else 和 switch 循环。因此,只要输出是 HTML,就应该始终使用 HTML 模板包而不是文本模板。
Golang 中的零值 Nil
发布时间:2023/04/27 浏览次数:166 分类:Go
-
本篇文章介绍 nil 在 Golang 中的含义,nil 是 Go 编程语言中的零值,是众所周知且重要的预定义标识符。
Golang 中的 Lambda 表达式
发布时间:2023/04/27 浏览次数:93 分类:Go
-
本篇文章介绍如何在 Golang 中创建 lambda 表达式。Lambda 表达式似乎不存在于 Golang 中。 函数文字、lambda 函数或闭包是匿名函数的另一个名称。
在 Go 中捕获 Panics
发布时间:2023/04/27 浏览次数:66 分类:Go
-
像错误一样,Panic 发生在运行时。 换句话说,当您的 Go 程序中出现意外情况导致执行终止时,就会发生 Panics。让我们看一些例子来捕捉 Golang 中的Panics。
在 Go 中使用断言
发布时间:2023/04/27 浏览次数:181 分类:Go
-
本篇文章介绍了 assert 在 GoLang 中的使用。在 Go 语言中使用断言:GoLang 不提供对断言的任何内置支持,但我们可以使用来自 Testify API 的广泛使用的第三方包断言。
Go 中的随机数生成
发布时间:2023/04/27 浏览次数:114 分类:Go
-
本篇文章介绍如何在 Go 语言中使用随机数生成功能。Go 中的随机数生成 Go 语言为随机数生成功能提供内置支持。 内置包 math 有方法 rand(),用于随机数生成。