Почему компилятор Swift помечает это как ошибку? - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть два способа написания одного и того же кода, один из которых не нравится компилятору Swift. Не могли бы вы объяснить, почему?

Контекст:

let guaranteedValue: String
let cursorPositionFromEnd: Int

Рабочий код:

let stringFromEndUntilCursorPosition = String(guaranteedValue.reversed()[0..<cursorPositionFromEnd])

Нерабочий код:

let reversedOriginalString = guaranteedValue.reversed()
let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])

Сообщение об ошибке компилятора: «Невозможно добавить значение типа ReversedCollection<String> с индексом типа Range<Int>»

Другая попытка работы:

let reversedOriginalString = guaranteedValue.reversed()[0..< cursorPositionFromEnd]
let stringFromEndUntilCursorPosition = String(reversedOriginalString)

По сути, идея заключается в том, что вы можете использовать только обратный диапазон (но, вероятно, не только), если вы добавляете индекс при возврате функции, но это не работает, если вы сначала ссылаетесь на переменную с помощью let или var, а затем пытаетесь подписать это.

Я также понимаю, что он, вероятно, будет работать в «нерабочем коде», если Range будет иметь тип String.Index или что-то новое, как это делается.

Может кто-нибудь объяснить, почему? Это ошибка в компиляторе Swift, у которого уже есть достаточно «искривленной» строковой логики?

1 Ответ

0 голосов
/ 15 ноября 2018

Существует несколько reversed() методов, как объяснено в Какие проблемы могут привести к тому, что метод reversed () может привести к быстрому массиву? .

В вашем первом примере кода,

let stringFromEndUntilCursorPosition = String(guaranteedValue.reversed()[0..<cursorPositionFromEnd])

компилятор выводит из контекста (то есть нижний индекс), что Sequence.reversed() метод, который возвращает массив. Массивы индексируются целыми числами, поэтому код компилируется. Этот метод имеет O(n) сложность, потому что создан новый массив со всеми элементами.

В

let reversedOriginalString = guaranteedValue.reversed()

такого контекста нет, и компилятор выбирает Bidirectional.reversed() метод. По сравнению с вышеупомянутым методом этот O(1) сложность. Возвращает ReversedCollection, который имеет свой собственный тип индекса, поэтому

let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])

выдает сообщение об обнаруженной ошибке.

Возможные решения:

  • Предоставить контекст для принудительного создания массива:

    let reversedOriginalString: [Character] = guaranteedValue.reversed()
    // Or: let reversedOriginalString: Array = guaranteedValue.reversed()
    // Or: let reversedOriginalString = guaranteedValue.reversed() as Array
    let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])
    

    Это работает, но имеет недостаток в создании временного массива.

  • Выполните правильные вычисления индекса для обращенной коллекции:

    let reversedOriginalString = guaranteedValue.reversed()
    let pos = reversedOriginalString.index(reversedOriginalString.startIndex, offsetBy: cursorPositionFromEnd)
    let stringFromEndUntilCursorPosition = String(reversedOriginalString[..<pos])
    

    Это позволяет избежать промежуточного массива, но утомительно писать.

  • Используйте метод последовательностей prefix(maxLength:):

    let reversedOriginalString = guaranteedValue.reversed()
    let stringFromEndUntilCursorPosition = String(reversedOriginalString.prefix(cursorPositionFromEnd))
    
...