Почему я не могу перебрать себя в расширении Range? - PullRequest
4 голосов
/ 01 мая 2019

У меня есть это расширение:

extension Range {
    func foo() { // called with (0..<5).foo()

        let bar = 0..<5

        print(bar) // 0..<5
        print(self) // 0..<5

        print(type(of: bar)) // Range<Int>
        print(type(of: self)) // Range<Int>

        for i in bar { // :)

        }

        for j in self { // :(

        }
    }
}

По какой-то причине первый цикл в порядке, а второй - нет. Я получаю сообщение об ошибке компиляции:

Type 'Bound' does not conform to protocol 'Strideable'  

Здесь также интересно отметить, что присвоение bar с self приводит к появлению ошибки в первом цикле.

Ответы [ 2 ]

5 голосов
/ 01 мая 2019

Укажите компилятору, что Bound равен Strideable:

extension Range where Element: Strideable {
    ...
}

Для определения Range требуется, чтобы Bound был только Comparable.См. Фактическую реализацию здесь .Comparable является минимальным требованием для определения Range.

Существует два типа диапазонов:

  • CoutableRange s: это диапазоны по типам (Bound), которые соответствуют Strideable и используют целочисленные шагимежду элементами.Эти диапазоны обрабатываются как Sequence и, следовательно, могут использоваться в цикле for.

  • Нормальный диапазоны: к ним относятся Range и ClosedRange только с Comparable элементами и, следовательно, не может быть повторен.

Это явно указано в этом комментарии.

4 голосов
/ 01 мая 2019

В примере bar компилятор знает, что bar равно 0..<5. Но в примере self компилятор не знает, что будет self.

Теперь рассмотрим этот код:

for i in 0.0..<1.0 {}

Не компилируется. Почему бы и нет? Потому что само понятие циклирования через диапазон Double с for...in не имеет смысла.

Что ж, в вашем коде компилятор не знает, что ваш Range (self) не будет диапазоном Double. Вы должны гарантировать , что этого не будет. Таким образом, вы должны указать, что ваше расширение должно работать только тогда, когда диапазон является чем-то, для чего for...in имеет смысл.

Вы могли бы сделать это, указав, что это будет диапазон Int или SignedInteger, но самый общий способ указать это, сказав, что ваш диапазон будет диапазоном Strideable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...