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

时间:2019-01-26 03:44:30

标签: swift functional-programming composition

我需要一系列函数,这些函数可以在字符串数组上工作以生成其他字符串数组...

说我开始:

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

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

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

print( animals.flatMap { $0.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  { $0.endsIn("t") } )
//endsIn
//endsIn
//endsIn
//["ant", "cat"]

我想组成这些功能,并且由于可能性范围很大,所以我想让所有事情保持懒惰:

let lazyComposition = animals
  .lazy
  .flatMap { $0.double() }
  .filter  { $0.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 { $0.double() }
        .filter  { $0.endsIn("t") }

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

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

但是在标记为#ERROR#的行上出现错误:类型'LazyFilterCollection ,[String]>>>'的值没有成员'next'

任何帮助解决此问题的方法。 或者,建议采用其他方法来实现这一目标。 谢谢 阿达修斯

1 个答案:

答案 0 :(得分:1)

首先,SequenceCollection不能用作Iterator,因此这部分代码是如此令人困惑:

  var iterator = self
    .lazy
    .flatMap { $0.double() }
    .filter  { $0.endsIn("t") }

局部变量iteratorCollection(具体来说,当您收到错误消息时,它是LazyFilterCollection <...>),而不是Iterator

第二,AnySequenceAnyIterator将Element类型作为其通用参数。

修正了以上两点之后,您可以编写如下内容:

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 { $0.double() }
                .filter  { $0.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