我正在尝试做这样的事情..
static var recycle: [Type: [CellThing]] = []
但是 - 我不能:)
Undeclared type 'Type'
在示例中,CellThing
是我的基类,因此 A:CellThing
、B:CellThing
、C:CellThing
等等。我的想法是我将在字典数组中存储各种 A A A、B B、C C C C。
如何使“类型”(我猜最好是仅限于 CellThing)成为 Swift 字典中的键?
我很感激我可以(也许?)使用String(describing: T.self)
,但这会让我失眠。
这是一个用例,设想的代码看起来像这样......
@discardableResult class func make(...)->Self {
return makeHelper(...)
}
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
return c
}
那么就像......
static var recycle: [Type: [CellThing]] = []
private class func makeHelper<T: CellThing>(...)->T {
let c = instantiateViewController(...) as! T
let t = type whatever of c (so, maybe "A" or "B")
recycle[t].append( c )
let k = recycle[t].count
print wow, you have k of those already!
return c
}
最佳答案
不幸的是,元类型类型目前不可能符合协议(protocol)(请参阅 this related question 关于此事) - 因此 CellThing.Type
目前没有也不可能符合 Hashable
。因此,这意味着它不能直接用作 Dictionary
的 Key
。
但是,您可以使用ObjectIdentifier
为元类型创建包装器。为了提供 Hashable
实现。例如:
/// Hashable wrapper for a metatype value.
struct HashableType<T> : Hashable {
static func == (lhs: HashableType, rhs: HashableType) -> Bool {
return lhs.base == rhs.base
}
let base: T.Type
init(_ base: T.Type) {
self.base = base
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(base))
}
// Pre Swift 4.2:
// var hashValue: Int { return ObjectIdentifier(base).hashValue }
}
然后,您还可以在 Dictionary
上提供一个方便的下标,它接受元类型并将其包装在 HashableType
中:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
set { self[HashableType(key)] = newValue }
}
}
然后可以像这样使用:
class CellThing {}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.self] = [A(), A(), A()]
recycle[B.self] = [B(), B()]
print(recycle[A.self]!) // [A, A, A]
print(recycle[B.self]!) // [B, B]
这对于泛型也应该可以正常工作,您只需使用 T.self
为字典添加下标即可。
不幸的是,在此处使用带有 get
和 set
的下标的一个缺点是,在使用复制的字典值时会导致性能下降 -编写诸如 Array
之类的类型(例如在您的示例中)。我多讲讲这个问题in this Q&A.
一个简单的操作,例如:
recycle[A.self]?.append(A())
将触发存储在字典中的数组的 O(N) 副本。
这是一个旨在通过 generalised accessors 解决的问题,它们已在 Swift 5 中作为非官方语言功能实现。如果您习惯使用可能在未来版本中出现问题的非官方语言功能(不真正推荐用于生产代码),那么您可以实现下标为:
extension Dictionary {
subscript<T>(key: T.Type) -> Value? where Key == HashableType<T> {
get { return self[HashableType(key)] }
_modify {
yield &self[HashableType(key)]
}
}
}
这解决了性能问题,允许数组值在字典内就地改变。
否则,一个简单的替代方案是不定义自定义下标,而只是在您的类型上添加一个方便的计算属性以让您将其用作键:
class CellThing {
// Convenience static computed property to get the wrapped metatype value.
static var hashable: HashableType<CellThing> { return HashableType(self) }
}
class A : CellThing {}
class B : CellThing {}
var recycle: [HashableType<CellThing>: [CellThing]] = [:]
recycle[A.hashable] = [A(), A(), A()]
recycle[B.hashable] = [B(), B()]
print(recycle[A.hashable]!) // [A, A, A]
print(recycle[B.hashable]!) // [B, B]
关于swift - 制作一个 Swift 字典,其中键是 "Type"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44448408/