下面是工作全局函数使用来自ReactiveCocoa的SignalProducer类,但对于任何泛型类而言,该原则应该是相同的。
func ignoreNilValues< Value,Error> (生产者:SignalProducer<值?,错误>) - > SignalProducer<值,错误> { return producer.filter {return $ 0!= nil} .map {$ 0! } }更新:
我已经取得了进展,但仍未达成完整的解决方案。 给定任何具有某种通用类的类property
class GenericClass< SomeType> { var someProperty:[SomeType] = [] }我写了一个扩展,它将过滤任何可选值,并使用 Wrapped 类型返回值?
以下将过滤所有nil值,但仍然返回它作为可选类型。
protocol AnOptional { var isNil:Bool {获得} } 扩展可选:AnOptional { var isNil:Bool { get { guard let hasValue = self.map({(value :Wrapped) - > Bool in return true })else { return true } return!hasValue } 扩展名GenericClass其中SomeType:AnOptional { func filterNilValuesOfSomeProperty() - > [SomeType] {返回someProperty.filter({(anOptional:AnOptional) - > Bool in return!anOptional.isNil })} } $可以看出, let aClass = GenericClass< Int?>() aClass.someProperty = [3,5,6,零,4,3,6,零] let x = aClass.someProperty // x = [Some(3),Some(5),Some(6),nil,Some(4),Some(3),Some(6) ,nil] let y = aClass.filterNilValuesOfSomeProperty() // y = [Some(3),Some(5),Some(6),Some(4),Some( 3),Some(6)]
是否可以编写一个类扩展,类型?在上面的例子中,它会是 [Int] 而不是 [Int?] 。
我为本示例重写了全局函数解决方案。
func ignoreNilValues< Value> (aClass:GenericClass< Value?>) - > GenericClass<值> { let aNewClass = GenericClass< Value>() aNewClass.someProperty = aClass.someProperty.filter({(v:Value?) - > Bool in v!= nil })。map {(oldValue:Value?) - > 中的值返回oldValue! } return aNewClass } let z = ignoreNilValues(aClass).someProperty // z = [3,5, 6,4,3,6]解决方案
是定义一个协议,所有的可选项符合(这是从创建一个扩展来过滤来自Swift中的数组的子元素 并进行小的简化;这个想法可以回到
c $ c> protocol OptionalType { typealias包装 func intoOptional() - >包裹? } 扩展可选:OptionalType { func intoOptional() - >包裹? { return self } }您可以使用在你的情况下:
class GenericClass< SomeType> { var someProperty:[SomeType] = [] } 扩展名GenericClass其中SomeType:OptionalType { func filterNilValuesOfSomeProperty() - > [SomeType.Wrapped] { return someProperty.flatMap {$ 0.intoOptional()} } }使用 SequenceType 中的 flatMap()方法:
extension SequenceType { ///返回包含非零映射结果的`Array` ///通过`self`转换。 /// /// - 复杂度:O(* M * + * N *),其中* M *是`self`的长度 ///和* N *是结果的长度。 @warn_unused_result public func flatMap< T>(@ noescape transform:(Self.Generator.Element)throws - > T?)rethrows - > [T] }示例:
let aClass = GenericClass< Int?>() aClass.someProperty = [3,5,6,nil,4,3,6,nil] $ (3),可选项(5),可选项(6),可选项(4),可选项(3),可选项(6) ,可选(6),无] 让y = aClass.filterNilValuesOfSomeProperty() print(y)// [3,5,6,4,3,6]在 Swift 3 中,协议必须定义为
protocol OptionalType { associatedtype Wrapped func intoOptional() - >包裹? }
So far I have only been able to achieve this using a global function. I am not sure if it is possible but I was hoping to write an extension to a generic class that would hopefully achieve the same thing.
Below is the working global function it is using SignalProducer class from ReactiveCocoa but the principle should be the same for any generic class.
func ignoreNilValues <Value,Error> (producer: SignalProducer<Value?,Error>) -> SignalProducer<Value, Error> { return producer.filter { return $0 != nil }.map { $0! } }Update:
I have made progress but have still fallen short of a complete solution
Given any class with some generic property
class GenericClass<SomeType> { var someProperty: [SomeType] = [] }How can I write an extension that will filter any optional values and return the value using the Wrapped type?
The following will filter any nil values but still return it as the Optional type.
protocol AnOptional { var isNil: Bool {get} } extension Optional : AnOptional { var isNil: Bool { get { guard let hasValue = self.map({ (value: Wrapped) -> Bool in return true }) else { return true } return !hasValue } } } extension GenericClass where SomeType : AnOptional { func filterNilValuesOfSomeProperty() -> [SomeType] { return someProperty.filter({ (anOptional: AnOptional) -> Bool in return !anOptional.isNil }) } }As can be seen
let aClass = GenericClass<Int?>() aClass.someProperty = [3,5,6,nil,4,3,6, nil] let x = aClass.someProperty //x = [Some(3),Some(5),Some(6),nil,Some(4),Some(3),Some(6), nil] let y = aClass.filterNilValuesOfSomeProperty() //y = [Some(3),Some(5),Some(6),Some(4),Some(3),Some(6)]Is it possible to write a class extension that would return the wrapped type? In the example above it would be [Int] instead of [Int?].
I rewrote the global function solution for this example.
func ignoreNilValues <Value> (aClass: GenericClass<Value?>) -> GenericClass<Value> { let aNewClass = GenericClass<Value>() aNewClass.someProperty = aClass.someProperty.filter({ (v: Value?) -> Bool in v != nil }).map { (oldValue: Value?) -> Value in return oldValue! } return aNewClass } let z = ignoreNilValues(aClass).someProperty //z = [3, 5, 6, 4, 3, 6]解决方案
The "trick" is to define a protocol to which all optionals conform (this is from Creating an extension to filter nils from an Array in Swift with a minor simplification; the idea goes back to this Apple Forum Thread):
protocol OptionalType { typealias Wrapped func intoOptional() -> Wrapped? } extension Optional : OptionalType { func intoOptional() -> Wrapped? { return self } }You can use that in your case as:
class GenericClass<SomeType> { var someProperty: [SomeType] = [] } extension GenericClass where SomeType : OptionalType { func filterNilValuesOfSomeProperty() -> [SomeType.Wrapped] { return someProperty.flatMap { $0.intoOptional() } } }which uses the flatMap() method from SequenceType:
extension SequenceType { /// Return an `Array` containing the non-nil results of mapping /// `transform` over `self`. /// /// - Complexity: O(*M* + *N*), where *M* is the length of `self` /// and *N* is the length of the result. @warn_unused_result public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T] }Example:
let aClass = GenericClass<Int?>() aClass.someProperty = [3,5,6,nil,4,3,6, nil] let x = aClass.someProperty print(x) // [Optional(3), Optional(5), Optional(6), nil, Optional(4), Optional(3), Optional(6), nil] let y = aClass.filterNilValuesOfSomeProperty() print(y) // [3, 5, 6, 4, 3, 6]In Swift 3 and later the protocol has to be defined as
protocol OptionalType { associatedtype Wrapped func intoOptional() -> Wrapped? }
更多推荐
我该如何编写一个函数,它将在swift中展开一个通用属性,假设它是一个可选类型?
发布评论