我一直在尝试从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
答案 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
已重命名为Collection
,Generator
现为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"]