首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >协议Swift 4字典

协议Swift 4字典
EN

Stack Overflow用户
提问于 2018-03-25 19:09:46
回答 3查看 1.4K关注 0票数 3

我有一个叫做可播放的协议,它需要func play()的实现。类DamageDrawACard都符合协议。

代码语言:javascript
复制
protocol Playable: class {
    func play(game: Game, value: Int) -> Player
}


class Damage: Playable, Hashable, Equatable {

    var hashValue: Int = 1

    static func ==(lhs: Damage, rhs: Damage) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }

    func play(game: Game, value: Int) -> Player {
        // do stuff
        return game.activePlayer
    }
}

class DrawACard: Playable, Equatable, Hashable {

    var hashValue: Int = 2

    static func ==(lhs: DrawACard, rhs: DrawACard) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }

    func play(game: Game, value: Int) -> Player {
        // do stuff
        return game.activePlayer
    }
}

我的问题如下:

代码语言:javascript
复制
class Card {
    var id: Int
    var name: String
    var cost: Int
    var description: String
    var target: Target
    var abilities: [Playable: Int]
    var cardType: CardType

    init(id: Int, name: String, cost: Int, description: String, cardType: CardType, target: Target, abilities: [Playable: Int]) {
        self.id = id
        self.name = name
        self.cost = cost
        self.description = description
        self.cardType = cardType
        self.abilities = abilities
        self.target = target
    }
}

abilities中的第6个变量在我尝试将协议作为密钥时抛出一个错误。它给了我:Type 'Playable' does not conform to protocol 'Hashable'

我希望能力变量具有实现Playable的对象的键和Int的值,例如。abilities = [DrawACard: 5]

我该怎么做呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-03-25 19:20:01

这种具有类继承的混合协议非常复杂。您的具体问题的答案是您不能直接这样做,因为如果您使Playable符合Hashable,那么您就不能创建它们的数组。

最简单的解决方案是这里不使用协议。做个抽象的课。Swift不太擅长抽象类,但它们将使这些问题大部分消失。

考虑到您的具体情况,我还可以考虑对Playable使用枚举,而不是使用协议。这可能会使事情变得更简单。

从那以后,解决方案就变得更加复杂了。例如,您可以按照我的ClassDictionary实验的思路创建一个ClassSet。或者你可以做一个类型橡皮。但事情变得很丑陋。

您还可以考虑从类切换到结构,去掉字典,只使用Array。如果Int的点是计数,那么只需拥有结构的多个副本。如果Int的点是一个参数(比如“多少损坏”),那么这应该在Damage结构中,而不是在字典中。

(不相关的注意,您的散列值非常奇怪。它们会起作用的,但哈希不是这样工作的。)

举个例子,我看到的是:

代码语言:javascript
复制
protocol Playable {
    func play(game: Game) -> Player
}

struct Damage: Playable {
    let amount: Int

    func play(game: Game) -> Player {
        // do stuff
        return game.activePlayer
    }
}

struct DrawACard: Playable {
    func play(game: Game) -> Player {
        // do stuff
        return game.activePlayer
    }
}

struct Card {
    let id: Int
    let name: String
    let cost: Int
    let description: String
    let cardType: CardType
    let target: Target
    let abilities: [Playable]
}

// A card that inflicts one damage
let card = Card(id: 1,
                name: "Strike",
                cost: 1,
                description: "Strike 'em",
                cardType: CardType(),
                target: Target(),
                abilities: [Damage(amount: 1)])

这是有意将所有内容转换为不可变的结构;我相信这里所描述的一切实际上都是值类型。

票数 2
EN

Stack Overflow用户

发布于 2018-03-25 19:47:56

我会将类的定义更改为此,这样类继承自一个Hashable基类:

代码语言:javascript
复制
class PlayableClass: Hashable {

    var hashValue: Int = 0

    static func ==(lhs: PlayableClass, rhs: PlayableClass) -> Bool {
        return true
    }
}

class Damage: PlayableClass, Playable {

    override init() {
        super.init()
        hashValue = 1
    }

   ...
}

class DrawACard: PlayableClass, Playable {

    override init() {
        super.init()
        hashValue = 2
    }

    ...
}

class Card {
    ...
    var abilities: [PlayableClass: Int]
    ...

    init(id: Int, name: String, cost: Int, description: String, abilities: [PlayableClass: Int]) {
        ...
    }
}
票数 0
EN

Stack Overflow用户

发布于 2020-09-07 18:00:01

这可能不会直接回答这个问题,但是,它可能会对这个问题的未来读者有所帮助。

一个想法是使用AnyHashable并使用强制转换来获取/设置所需的内容。

定义你的字典:

代码语言:javascript
复制
var abilities: [AnyHashable: Int] = [:]

然后创建一些方法来添加/删除字典中的项。

代码语言:javascript
复制
func addPlayable<T: Playable>(_ myPlayable: T) where T:Hashable {
    abilities[myPlayable] = 0
}

func removePlayable<T: Playable>(_ myPlayable: T) where T:Hashable {
    abilities.removeValue(forKey: myPlayable)
}

访问这样的元素:

代码语言:javascript
复制
func getValue<T: Playable>(_ obj: T) -> Int? where T:Hashable {
    return abilities[obj]
}

或者,如果您想迭代字典,可以这样做:

代码语言:javascript
复制
abilities.forEach { (it) in
    (it.key as? Playable)?.play(...)
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49479839

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档