Swift中的泛型数组

贝克·史密斯

我一直在研究具有不同类型的泛型类的数组。用一些示例代码来解释我的问题是最简单的:

// Obviously a very pointless protocol...
protocol MyProtocol {
    var value: Self { get }
}

extension Int   : MyProtocol {  var value: Int    { return self } }
extension Double: MyProtocol {  var value: Double { return self } }

class Container<T: MyProtocol> {
    var values: [T]

    init(_ values: T...) {
        self.values = values
    }

    func myMethod() -> [T] {
        return values
    }
}

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

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

我得到错误:

协议“ MyProtocol”只能用作通用约束,因为它具有“自身”或关联的类型要求。

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

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

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

for container in containers {
    if let c = container as? Container<Int> {
        println(c.myMethod())

    } else if let c = container as? Container<Double> {
        println(c.myMethod())
    }
}

如您在上面的代码中所看到的,container在两种情况下,确定相同方法的类型后都会被调用。我的问题是:

是否有Container比将类型转换为每种可能的类型更好的方法来获取正确的类型Container还是我忽略了其他事情?

亚伦·拉斯穆森(Aaron Rasmussen)

有一种方法-做某事-一种。使用协议,有一种方法可以消除类型限制,并且仍然可以得到所需的结果,但这并不总是很漂亮。这是我根据您的情况提出的协议:

protocol MyProtocol {
    func getValue() -> Self 
}

extension Int: MyProtocol {
    func getValue() -> Int {
        return self
    }
}

extension Double: MyProtocol {
    func getValue() -> Double {
        return self
    }
}

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

那不是很有趣。

但是现在,由于您已经摆脱value了协议中的属性,因此MyProtocol可以将其用作类型,而不仅仅是类型约束。您的Container班级甚至都不再需要泛型。您可以这样声明:

class Container {
    var values: [MyProtocol]

    init(_ values: MyProtocol...) {
        self.values = values
    }

    func myMethod() -> [MyProtocol] {
        return values
    }
}

而且由于Container不再通用,因此您可以创建一个的ArrayContainer并对其进行迭代,从而打印该myMethod()方法的结果

var containers = [Container]()

containers.append(Container(1, 4, 6, 2, 6))
containers.append(Container(1.2, 3.5))

for container in containers {
    println(container.myMethod())
}

//  Output: [1, 4, 6, 2, 6]
//          [1.2, 3.5]

诀窍在于构造仅包含通用功能且对符合类型没有其他要求的协议如果您可以避免这样做,那么可以将协议用作类型,而不仅仅是类型约束。

另外(如果您想这样称呼),您的MyProtocol数组甚至可以混合符合的不同类型MyProtocol因此,如果您给出这样StringMyProtocol扩展名:

extension String: MyProtocol {
    func getValue() -> String {
        return self
    }
}

您实际上可以Container使用混合类型初始化a

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

[警告-我正在其中一个在线游乐场进行测试。我还不能在Xcode中对其进行测试...]

编辑:

如果你仍然想Container成为通用的,只能容纳一个类型的对象,就可以完成,通过使符合自己的协议:

protocol ContainerProtocol {
    func myMethod() -> [MyProtocol]
}

class Container<T: MyProtocol>: ContainerProtocol {
    var values: [T] = []

    init(_ values: T...) {
        self.values = values
    } 

    func myMethod() -> [MyProtocol] {
        return values.map { $0 as MyProtocol }
    }
}

现在,您仍然可以拥有一个[ContainerProtocol]对象数组,并通过调用它们进行迭代myMethod()

let containers: [ContainerProtocol] = [Container(5, 3, 7), Container(1.2, 4,5)]

for container in containers {
    println(container.myMethod())
}

也许这仍然对您不起作用,但是现在Container仅限于一种类型,但是您仍然可以遍历ContainterProtocol对象数组

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章