Подтвердить что ты не робот

Тип '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? Спасибо!

4b9b3361

Ответ 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))