在Swift中扩展SequenceType

时间:2015-11-07 11:05:39

标签: swift generics sequence

我想知道为什么map()filter() SequenceType同时返回Array。 实际上,我并不认为这是必要的。再次返回序列对我来说更加明智。

但是,在尝试添加顺序版本时,我遇到了困难。这是我对地图的尝试:

extension SequenceType {

   func seqMap<T, S: SequenceType where S.Generator.Element == T>(
        transform: Self.Generator.Element -> T) -> S 
   {
        var sourceGen = generate()
        let tGen: AnyGenerator<T> = anyGenerator {
            if let el = sourceGen.next() {
                return transform(el)
            } else {
                return nil
            }
        }
        return AnySequence { tGen }
    }
}

XCode在最后一个return语句中告诉我以下错误:

cannot invoke initializer for type 'AnySequence<T>' with an argument list of type '(() -> AnyGenerator<T>)'
note: overloads for 'AnySequence<T>' exist with these partially matching parameter lists: (S), (() -> G)

实际上,我的tGen类型为() -> G,为什么XCode认为它不明确?

1 个答案:

答案 0 :(得分:3)

如果拆分return语句,问题就会变得更加明显:

let tSeq = AnySequence { tGen }
return tSeq // error: cannot convert return expression of type 'AnySequence<T>' to return type 'S'

编译器会从上下文中推断出占位符类型S 方法调用,可以是任何序列 元素类型为T的类型,不一定是AnySequence

这是一个展示同样问题的简单示例:

protocol MyProtocol { }
struct MyType { }
extension MyType : MyProtocol { }

func foo<P : Protocol>() -> P {
    return MyType() // error: cannot convert return expression of type 'MyType' to return type 'P'
}

要解决此问题,请将返回类型更改为AnySequence<T> 并删除泛型类型S

extension SequenceType {

    func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
    {
        var sourceGen = generate()
        let tGen: AnyGenerator<T> = anyGenerator {
            if let el = sourceGen.next() {
                return transform(el)
            } else {
                return nil
            }
        }
        return AnySequence { tGen }
    }
}

可以更紧凑地编写

extension SequenceType {

    func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
    {
        var sourceGen = generate()
        return AnySequence(anyGenerator {
            sourceGen.next().map(transform)
        })
    }
}

使用map()类型的Optional方法。

但请注意SequenceType已经有一个lazy方法返回 LazySequenceType

/// A sequence containing the same elements as a `Base` sequence, but
/// on which some operations such as `map` and `filter` are
/// implemented lazily.
///
/// - See also: `LazySequenceType`
public struct LazySequence<Base : SequenceType> 

你可以使用

someSequence.lazy.map { ... }

获得(延迟评估的)映射值序列。