swift - 制作一个 Swift 字典,其中键是 "Type"?

标签 swift dictionary types

我正在尝试做这样的事情..

static var recycle: [Type: [CellThing]] = []

但是 - 我不能:)

enter image description here

Undeclared type 'Type'

在示例中,CellThing 是我的基类,因此 A:CellThingB:CellThingC: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 。因此,这意味着它不能直接用作 DictionaryKey

但是,您可以使用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 为字典添加下标即可。

<小时/>

不幸的是,在此处使用带有 getset 的下标的一个缺点是,在使用复制的字典值时会导致性能下降 -编写诸如 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/

相关文章:

swift - 如何在每次内容 View 加载时生成一个新的随机数?

python - 在python中读取/写入字典到csv文件

javascript - 展平对象属性列表

types - 标准 ML 二叉树类型

c# - 如何在 C# 中创建自定义类型的数组?

swift - CloseButton怎么能有这样的表现

swift - 无法更新数组中字典中的值?

python - python中根据key值组合字典

go - 将 Golang 定义的类型视为基础类型?

swift - 转到详细的 TableView Controller