如何封装 Lazy Swift 函数的组合?

How can I encapsulate composition of Lazy Swift Functions?

我需要一系列函数来处理字符串数组以生成其他字符串数组...

假设我开始于:

let animals = ["ant", "bear", "cat"]

有些函数会增加数组中的元素。例如:

extension String {
  func double() -> [String] {
    print("double")
    return [self, self]
  }
}

print( animals.flatMap { [=12=].double() } )
//double
//double
//double
["ant", "ant", "bear", "bear", "cat", "cat"]

有的会减少元素的数量。例如:

extension String {
  func endsIn(_ endString: String) -> Bool {
    print("endsIn")
    return hasSuffix(endString)
  }
}

print( animals.filter  { [=13=].endsIn("t") } )
//endsIn
//endsIn
//endsIn
//["ant", "cat"]

我想组合这些函数,因为可能性的范围很大,所以我想尽量保持惰性:

let lazyComposition = animals
  .lazy
  .flatMap { [=14=].double() }
  .filter  { [=14=].endsIn("t") }

for x in lazyComposition {
  print(">>>>>>>>>>> \(x)")
}
//double
//endsIn
//  >>>>>>>>>>> ant
//endsIn
//  >>>>>>>>>>> ant
//double
//endsIn
//endsIn
//double
//endsIn
//  >>>>>>>>>>> cat
//endsIn
//  >>>>>>>>>>> cat

我想封装这个函数组合。 我想我快到了:

extension Array where Element == String {
  func combined() -> AnySequence<[String]> {

    return AnySequence<[String]> { () -> AnyIterator<[String]> in
      var iterator = self
        .lazy
        .flatMap { [=15=].double() }
        .filter  { [=15=].endsIn("t") }

      return AnyIterator {
        return iterator.next()    // #ERROR#
      }
    }
  }
}

for x in animals.combined() {
  print(">>>>>>>>>>> \(x)")
}

但我在标记为#ERROR# 的行上收到错误消息:'LazyFilterCollection < FlattenCollection < LazyMapCollection < Array < String > , [String] > > > ' 类型的值没有成员'next'

任何解决这个问题的帮助表示赞赏。 或者建议其他方法来实现这一目标。 谢谢 阿达胡斯

首先,SequenceCollection不能用作Iterator,所以你的这部分代码很混乱:

  var iterator = self
    .lazy
    .flatMap { [=10=].double() }
    .filter  { [=10=].endsIn("t") }

局部变量 iteratorCollection(具体来说是 LazyFilterCollection <...>,如您在错误消息中看到的那样),而不是 Iterator.

其次,AnySequenceAnyIterator 将元素类型作为其通用参数。

以上两点固定后,你可以这样写:

extension Array where Element == String {
    func combined() -> AnySequence<String> {

        return AnySequence<String> { () -> AnyIterator<String> in // <- specify Element type as `String`
            var iterator = self
                .lazy
                .flatMap { [=11=].double() }
                .filter  { [=11=].endsIn("t") }
                .makeIterator() // <- make `Iterator` from `Collection`

            return AnyIterator {
                return iterator.next()
            }
        }
    }
}

let animals = ["ant", "bear", "cat"]

for x in animals.combined() {
    print(">>>>>>>>>>> \(x)")
}

输出:

double
endsIn
>>>>>>>>>>> ant
endsIn
>>>>>>>>>>> ant
double
endsIn
endsIn
double
endsIn
>>>>>>>>>>> cat
endsIn
>>>>>>>>>>> cat