Как я могу инкапсулировать состав Lazy Swift Functions? - PullRequest
0 голосов
/ 26 января 2019

Мне нужен диапазон функций, которые будут работать с массивом строк для создания других массивов строк ...

Скажем, я начинаю с:

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]>>> 'не имеет члена' далее '

Любая помощь в исправлении этого приветствуется.Или, альтернативно, предлагая другие способы достижения этого.Спасибо Адахус

1 Ответ

0 голосов
/ 26 января 2019

Прежде всего, Sequence или Collection нельзя использовать как Iterator, поэтому эта часть вашего кода настолько запутана:

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

Локальная переменная iterator - это Collection (в частности, это LazyFilterCollection <...>, как вы видите в сообщении об ошибке), а не Iterator.

Во-вторых, AnySequence или AnyIterator принимает тип элемента для своего общего параметра.

Исправив две вещи выше, вы можете написать что-то вроде этого:

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
...