CompactMap на sequence () не ленивый?

Время от времени мне приходится ходить по цепочке респондентов, чтобы найти экземпляр известного класса. (Просто примите это для целей вопроса.) Я делал это с помощью цикла while, но мне пришло в голову, что было бы круче использовать sequence(), который может аккуратно выразить саму цепочку респондента следующим образом:

let chain = sequence(first: someView as UIResponder) {[110].next}

Это замечательно, потому что до сих пор мы на самом деле не ходили пешком; последовательность ленива, и анонимная функция не будет выполнена, пока мы не начнем запрашивать элементы. Чтобы доказать это, позвольте мне обработать этот код оператором print:

let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}

Хорошо, давайте предположим, что я ищу первый экземпляр ViewController в цепочке. Я могу найти это так:

if let vc = (chain.first {[112] is ViewController}) as? ViewController {
    print(vc)
}

Распечатка показывает, что лень сохраняется: мы шли по цепочке респондента, пока не добрались до ViewController и остановились. Отлично! Внутри фигурных скобок vc напечатано как ViewController, и мы отправляемся в гонки.

Однако это не ускользнуло от вашего внимания, потому что это безобразно. Я и тестирую и кастую. Есть ли способ, которым я могу просто привести без тестирования и все же получить ViewController?

Это элегантно и прекрасно работает:

for case let vc as ViewController in chain {
    print(vc)
    break
}

Это прекрасно, и лень сохраняется - но я не забудьте сказать break в конце, что все разрушает.

Хорошо, поэтому я очень надеялся, когда думал об этом:

if let vc = (chain.compactMap{ [114] as? ViewController }.first) {
    print(vc)
}

Это работает в том смысле, что он компилируется, получает правильный ответ и выглядит красиво, но я потерял лени . Весь chain проходит. compactMap теряет лень? Есть ли способ вернуть его? (Или есть какой-то другой элегантный способ, который полностью ускользнул от меня?)

2
задан matt 27 June 2019 в 01:02
поделиться

1 ответ

Проблема не compactMap по сути. Существует две проблемы:

  1. , Если Вы хотите, чтобы последовательность звонила compactMap лениво, необходимо использовать lazy .

  2. казалось бы, что first предотвращает ленивое поведение. Если Вы используете first(where:), тем не менее, Вы действительно наслаждаетесь ленивым поведением.

Таким образом, в то время как несколько неэлегантный, следующее достигает что поиск you’re:

if let vc = (chain.lazy.compactMap { [110] as? ViewController }.first { _ in true } ) {
    ...
} 

Или, как Вы говорите, можно реализовать first (или lazyFirst) на [1 110]:

extension Sequence {
    var first: Element? {
        return first { _ in true }
    }
}

И затем это более упрощенное представление теперь все еще лениво:

if let vc = chain.lazy.compactMap({ [112] as? ViewController }).first {
    ...
} 
1
ответ дан Rob 27 June 2019 в 01:02
поделиться
  • 1
    Моя любимая часть об этом ответе - то, что они непреднамеренно записали допустимую строку Python. – ArtOfWarfare 23 January 2016 в 22:31
Другие вопросы по тегам:

Похожие вопросы: