迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

在 Go 中如何使用泛型 入门 - 使用具有多种类型的泛型

作者:迹忆客 最近更新:2022/07/31 浏览次数:

没有泛型的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 仅包含卡片,则需要一种方法来限制允许的数据类型。

本站文章均为原创或翻译,转载请发邮件至 1244347461@qq.com 进行申请,未经许可,禁止转载。经作者同意之后,转载请以链接形式注明出处

本文地址:

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

热门文章

教程更新

热门标签

Go
扫码一下
查看教程更方便