Тип 'String.Index' не соответствует протоколу 'IntegerLiteralConvertible'
С Beta 3 все работало нормально, теперь я получаю странную ошибку, и я не знаю, как ее исправить. Пробовал все решения для подобных проблем.
Вот мой код:
if !name.isEmpty {
var splitted: [String] = name.componentsSeparatedByString(" ")
for curPart in splitted {
if !curPart.isEmpty {
acronym += curPart.substringToIndex(1) //Error
}
}
if (acronym as NSString).length > 2 {
acronym = acronym.substringToIndex(2) //Error
}
}
Обе отмеченные строки дали мне ту же ошибку:
Тип 'String.Index' не соответствует протоколу 'IntegerLiteralConvertible'
Может кто-нибудь мне помочь? Или бета-тестирование 4?
Спасибо!
Ответы
Ответ 1
В бета-версии 4 обработка Swift String.Index снова изменилась - теперь вы не можете поставить Int
, когда ожидается String.Index
. Способ справиться с этим - создать String.Index
, используя метод advance
:
if !name.isEmpty {
var splitted: [String] = name.componentsSeparatedByString(" ")
for curPart in splitted {
if !curPart.isEmpty {
acronym += curPart.substringToIndex(advance(curPart.startIndex, 1))
}
}
if countElements(acronym) > 2 {
acronym = acronym.substringToIndex(advance(acronym.startIndex, 2))
}
}
Все это основано на том, что строки Unicode обрабатываются правильно - поскольку разные символы Unicode могут иметь разные размеры, чистое целочисленное индексирование скроет тот факт, что строки не являются произвольным доступом.
Ответ 2
В Beta 4 изменилось понятие строковых компонентов и итераций. Из руководство мы видим:
Каждый экземпляр типа Swifts Character представляет собой единый расширенный кластер grapheme. Расширенный кластер grapheme представляет собой последовательность из одного или нескольких сканеров Unicode, которые (при объединении) создают один человекочитаемый символ.
У этого есть некоторые интересные побочные эффекты:
let str1 = "abc"
let str2 = "\u{20DD}def"
countElements(str1) // 3
countElements(str2) // 4
countElements(str1+str2) // 6 ≠ 3+4 !!!
Это потому, что c
и \u{20DD}
объединяются для формирования c⃝. Также обратите внимание, что мы используем countElements
. Чтобы выяснить длину строки, Swift на самом деле должен перебирать всю строку и вычислять, где находятся фактические графемные деления, поэтому требуется время O (n).
Мы также видим эффект от разных кодировок:
Array((str1+str2).utf8) // [97, 98, 99, 226, 131, 157, 100, 101, 102]
Array((str1+str2).utf16) // [97, 98, 99, 8413, 100, 101, 102]
Другая проблема, как говорит ваша ошибка, заключается в том, что String
IndexType
больше не может быть конвертирован из целочисленного литерала: вы не можете выполнить произвольный доступ к строке, указав смещение. Вместо этого вы можете использовать startIndex
и advance
для перемещения вперед некоторого расстояния в строке, например str[str.startIndex]
или str[advance(str.startIndex, distance)]
.
Или вы можете определить свои собственные вспомогательные функции тем временем:
func at<C: Collection>(c: C, i: C.IndexType.DistanceType) -> C.GeneratorType.Element {
return c[advance(c.startIndex, i)]
}
func take<C: protocol<Collection, Sliceable>>(c: C, n: C.IndexType.DistanceType) -> C.SliceType {
return c[c.startIndex..<advance(c.startIndex, n)]
}
at(str1+str2, 3) // d
take(str1+str2, 2) // ab
Очевидно, есть некоторые улучшения, которые могут (и, вероятно, будут) сделаны в будущих обновлениях. Вы можете захотеть указать ошибку в своих проблемах. В конечном счете, поддержка кластеров графем правильно, вероятно, было хорошим решением, но тем не менее он делает доступ к строке немного более болезненным тем временем.
Ответ 3
Для Swift 2.0
Используя приведенный выше пример:
curPart.substringToIndex(curPart.startIndex.advancedBy(1))