Swift中的泛型数组

前端之家收集整理的这篇文章主要介绍了Swift中的泛型数组前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直在玩不同类型的泛型类数组。最简单的解释我的问题与一些示例代码
  1. // ObvIoUsly a very pointless protocol...
  2. protocol MyProtocol {
  3. var value: Self { get }
  4. }
  5.  
  6. extension Int : MyProtocol { var value: Int { return self } }
  7. extension Double: MyProtocol { var value: Double { return self } }
  8.  
  9. class Container<T: MyProtocol> {
  10. var values: [T]
  11.  
  12. init(_ values: T...) {
  13. self.values = values
  14. }
  15.  
  16. func myMethod() -> [T] {
  17. return values
  18. }
  19. }

现在,如果我尝试创建一个容器数组,像这样:

  1. var containers: [Container<MyProtocol>] = []

我得到的错误

Protocol ‘MyProtocol’ can only be used as a generic constraint because it has Self or associated type requirements.

解决这个问题,我可以使用[AnyObject]:

  1. let containers: [AnyObject] = [Container<Int>(1,2,3),Container<Double>(1.0,2.0,3.0)]
  2. // Explicitly stating the types just for clarity.

但是现在在通过容器枚举时出现了另一个“问题”:

  1. for container in containers {
  2. if let c = container as? Container<Int> {
  3. println(c.myMethod())
  4.  
  5. } else if let c = container as? Container<Double> {
  6. println(c.myMethod())
  7. }
  8. }

正如你可以在上面的代码中看到的,在确定容器的类型后,在这两种情况下调用相同的方法。我的问题是:

有没有更好的方法来获得正确的类型的容器,而不是铸造到每一种可能的类型的容器?还是有其他我忽略了?

有一种方式 – 一种 – 做你想要的 – 那种。有一种方法,与协议,消除类型限制,仍然得到你想要的结果,种类,但它并不总是漂亮。这里是我提出了作为一个协议在你的情况:
  1. protocol MyProtocol {
  2. func getValue() -> Self
  3. }
  4.  
  5. extension Int: MyProtocol {
  6. func getValue() -> Int {
  7. return self
  8. }
  9. }
  10.  
  11. extension Double: MyProtocol {
  12. func getValue() -> Double {
  13. return self
  14. }
  15. }

请注意,您最初放入协议声明中的value属性已更改为返回对象的方法

这不是很有趣。

但是现在,因为你已经摆脱了协议中的value属性,MyProtocol可以作为一个类型,而不只是作为一个类型约束。你的Container类甚至不需要是通用的了。你可以这样声明:

  1. class Container {
  2. var values: [MyProtocol]
  3.  
  4. init(_ values: MyProtocol...) {
  5. self.values = values
  6. }
  7.  
  8. func myMethod() -> [MyProtocol] {
  9. return values
  10. }
  11. }

并且因为Container不再是通用的,你可以创建一个容器数组并迭代它们,打印myMethod()方法的结果:

  1. var containers = [Container]()
  2.  
  3. containers.append(Container(1,4,6,6))
  4. containers.append(Container(1.2,3.5))
  5.  
  6. for container in containers {
  7. println(container.myMethod())
  8. }
  9.  
  10. // Output: [1,6]
  11. // [1.2,3.5]

诀窍是构造一个只包括通用函数的协议,并且没有对符合类型的其他要求。如果你可以逃避这样做,那么你可以使用协议作为一个类型,而不只是作为一个类型约束。

并且作为奖励(如果你想调用它),MyProtocol值的数组甚至可以混合符合MyProtocol的不同类型。所以如果你给String一个MyProtocol扩展,像这样:

  1. extension String: MyProtocol {
  2. func getValue() -> String {
  3. return self
  4. }
  5. }

您可以实际初始化混合类型的容器:

  1. let container = Container(1,4.2,"no kidding,this works")

[警告 – 我在一个在线游乐场测试这个。我还没有能够在Xcode中测试…]

编辑:

如果你仍然希望Container是通用的并且只持有一种类型的对象,你可以通过使它符合自己的协议来实现:

  1. protocol ContainerProtocol {
  2. func myMethod() -> [MyProtocol]
  3. }
  4.  
  5. class Container<T: MyProtocol>: ContainerProtocol {
  6. var values: [T] = []
  7.  
  8. init(_ values: T...) {
  9. self.values = values
  10. }
  11.  
  12. func myMethod() -> [MyProtocol] {
  13. return values.map { $0 as MyProtocol }
  14. }
  15. }

现在你仍然可以有一个[ContainerProtocol]对象的数组,并通过调用myMethod()迭代:

  1. let containers: [ContainerProtocol] = [Container(5,3,7),Container(1.2,5)]
  2.  
  3. for container in containers {
  4. println(container.myMethod())
  5. }

也许仍然不能为你工作,但现在Container限制为一个单一的类型,但你仍然可以迭代通过一个ContainterProtocol对象数组。

猜你在找的Swift相关文章