【问题标题】:Swift dictionary key typeSwift 字典键类型
【发布时间】:2015-12-28 20:12:45
【问题描述】:

我有两个课程: CatHelper 和 DogHelper 都继承自 DataHelper 并且都只包含类函数。

我想要一本 [DataHelper : [String]] 类型的字典

为此,我让 DataHelper 符合 Hashable + Equatable

但是我很难实例化这样的字典。这是我到目前为止尝试过的

let apiURLS:[DataHelper : [String]] = [CatHelper : ["abc","def"], DogHelper:["ddd"], DogHelper: ["fff"]]

但编译器说“无法将 CatHelper.Type 类型的值转换为 DataHelper 类型的预期字典键”

编辑:

然后,我想遍历这个字典来做,在这个例子中

CatHelper.feed("abc")
CatHelper.feed("def")
DogHelper.feed("ddd")
DogHelper.feed("fff")

在这种情况下,拥有 CatHelper 或 DogHelper 的实例没有用,因为我只使用类函数。

【问题讨论】:

  • 编译器再次正确 - 您尝试传入实际的类/类型,而不是它的实例。那是行不通的。如果您提供更多背景信息,我们可能会提出更好的方法。
  • 我刚刚编辑了我的问题以提供更多上下文
  • 你能详细说明“为什么”吗?您希望一切都是静态的这一事实很痛苦:/
  • 好吧,我可以更改为非静态类,但这些是 Helpers,我认为 Helpers 应该是静态的,我看不出这些类是静态的原因

标签: swift inheritance polymorphism static-methods swift-dictionary


【解决方案1】:

因为你的字典是这样声明的

let apiURLS:[DataHelper : [String]]

这意味着密钥必须是DataHelper类型的实例。

要获取 DataHelper 类型的实例,您可以编写

DataHelper()

DataHelper 子类的实例也是有效的:

CatHelper()
DogHelper()

所以

let apiURLS:[DataHelper:[String]] = [
    CatHelper(): ["abc","def"],
    DogHelper(): ["ddd"],
    DogHelper(): ["fff"]
]

更新

从您的 cmets(和更新的问题)中,我看到您希望字典的键确实是类的类型,而不是实例。

我认为这是不可能的,因为

let apiURLS:[DataHelper.Type : [String]] = [
    CatHelper.self: ["abc","def"],
    DogHelper.self: ["ddd"],
    DogHelper.self: ["fff"]
]
error: type 'DataHelper.Type' does not conform to protocol 'Hashable'
let apiURLS:[DataHelper.Type : [String]] = [
        ^

所以我们不能使用类类型作为字典的键。

好的,让我们探索另一个解决方案

这个 Wrapper 可以包含DataHelper 的类型或DataHelper 的子类类型。

class Wrapper:Hashable, Equatable {
    let value: DataHelper.Type
    init(_ value:DataHelper.Type) {
        self.value = value
    }
    var hashValue: Int { get { return "\(value)".hashValue } }
}

func ==(left:Wrapper, right:Wrapper) -> Bool {
    return left.value == right.value
}

这样

Wrapper(CatHelper.self)

由于包装器是 Hashable 并且 Equatable 可以用作 Dictionary 中的键。

现在

let apiURLS:[Wrapper : [String]] = [
    Wrapper(CatHelper.self): ["abc","def"],
    Wrapper(DogHelper.self): ["ddd"],
    Wrapper(DogHelper.self): ["fff"]
]

迭代

apiURLS
    .map { ($0.0.value, $0.1) }
    .forEach { (classType, strings) -> () in
        classType.feed("Wow")
}

【讨论】:

  • 谢谢,但我不想拥有那些 Helper 的实例,因为我只使用静态类函数
【解决方案2】:

好的,经过一番摆弄后,它开始工作了:

let apiURLS:[(String -> (),[String])] = [(CatHelper.feed, ["abc","def"]), (DogHelper.feed, ["ddd"]), (DogHelper.feed, ["fff"])]

apiURLS.forEach { (f, x) in
    x.forEach {
        f($0)
    }
}

变化基本上是你不再有一个字典(由于重复的键,它一开始就不能工作)而是一个数组。在数组中,您有一个要调用的函数和输入的元组。

以下代码作为构建基线:

class DataHelper {
    class func feed(a:String) {
        print("data ate \(a)")
    }
}

class CatHelper : DataHelper {
    override class func feed(a:String) {
        print("cat ate \(a)")
    }
}

class DogHelper : DataHelper {
    override class func feed(a:String) {
        print("dog ate \(a)")
    }
}

输出

猫吃了 abc
猫吃了def
狗吃了ddd
狗吃了fff

【讨论】:

  • 哦,很酷,对你来说是不是有点生硬?有设计问题还是“正常”问题
  • @Max 它仍然是一个 bit hacky,但由于我不知道 feed 方法究竟会做什么以及实际输入来自哪里,我真的不能提供其他任何东西。
  • [String]的内容是URLS。我获取每个 url(json 对象),然后为每种 json 调用一个特定的 feed 方法。此方法提供一个 CoreData 对象并保存它
猜你喜欢
  • 2015-09-03
  • 2017-07-16
  • 2016-09-26
  • 2015-12-15
  • 1970-01-01
  • 2020-07-26
  • 2015-08-13
  • 1970-01-01
相关资源
最近更新 更多