如何在集合类型约束中生成泛型?

时间:2016-07-18 10:14:11

标签: ios swift generics optional

我一直在尝试从String数组中提取非零值。如下。但是,我的大四学生希望它能够从其他类型中提取非零值

我读过,泛型可以帮助我处理不同的类型。我如何使用泛型,以便我可以使用以下类似的扩展来与其他类型一起使用?

import Foundation // Extended the collection-type so that collectiontype is constrained to having element with optional strings extension CollectionType where Self.Generator.Element == Optional<String>{ func getNonNil() -> [String] { // filter out all nil elements and forcefully unwrap them using map return self.filter({$0 != nil}).map({$0!}) } } // Usage let x: [String?] = ["Er", "Err", nil, "errr"] x.getNonNil().forEach { (str) in print(str) } 必须返回特定类型的提取的非零值(即如果数组是[String?]它必须返回[String],如果[Int?]则返回[Int]强>)

因为我必须做进一步的计算。

我的尝试如下:

net.bat

3 个答案:

答案 0 :(得分:3)

对于getNonNil,您只需使用

即可
x.flatMap { $0 }
// returns ["Er", "Err", "errr"] which is [String]

对于原始问题,通常您可以向Optional类型引入协议(例如,通过muukii/OptionalProtocol包):

protocol OptionalProtocol {
    associatedtype Wrapped
    var value: Wrapped? { get }
}

extension Optional: OptionalProtocol {
    public var value: Wrapped? { return self }
}

extension CollectionType where Self.Generator.Element: OptionalProtocol {
    func getNonNil() -> [Self.Generator.Element.Wrapped] {
        ...
    }
}

答案 1 :(得分:2)

通过扩展没有简单的方法来实现这一点,因为你不能在扩展中引入新的泛型类型(虽然这是part of the Swift Generics Manifesto - 所以很可能在Swift的未来版本中。)

作为@kennytm says,最简单的解决方案就是使用flatMap来过滤掉nil

x.flatMap{$0}.forEach { (str) in
    print(str)
}

但是,如果您仍然希望将其作为扩展名,那么可以使用协议解决方法,以便允许您将扩展名约束为任何可选元素类型(Swift 3):

protocol _OptionalProtocol {
    associatedtype Wrapped
    func _asOptional() -> Wrapped?
}

extension Optional : _OptionalProtocol {
    func _asOptional() -> Wrapped? {return self}
}

extension Collection where Self.Iterator.Element : _OptionalProtocol {
    func getNonNil() -> [Iterator.Element.Wrapped] {
        return flatMap{$0._asOptional()}
    }
} 

...

let x : [String?] = ["Er", "Err", nil, "errr"]

x.getNonNil().forEach { (str) in
    print(str)
}

(在Swift 3中,CollectionType已重命名为CollectionGenerator现为Iterator

虽然在这种情况下flatMap几乎肯定是首选,但我只是为了完成而添加了这个。

答案 2 :(得分:0)

最简单的方法是使用flatMap作为 kennytm 建议,但如果你绝对想知道如何使用泛型创建这样的方法,一种方法是创建一个全局方法,将集合作为参数:

public func getNonNil<T, C: CollectionType where C.Generator.Element == Optional<T>>(collection: C) -> [T] {
    return collection.filter({$0 != nil}).map({$0!})
}

let x: [String?] = ["Er", "Err", nil, "errr"]

print(getNonNil(x)) // returns ["Er", "Err", "errr"]