Является ли String коллекцией в Swift?

«Является ли String коллекцией в Swift?» — вопрос из категории Swift Core, который задают на 22% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, начиная с Swift 4, String напрямую соответствует протоколу Collection. Более точно, String соответствует протоколу BidirectionalCollection, что позволяет эффективно перемещаться по его элементам в обоих направлениях.

Эволюция и детали:

  • Swift 3: String не был прямой коллекцией. Доступ к символам осуществлялся через свойство characters (String.CharacterView), которое было коллекцией.
  • Swift 4 и новее: String был переработан и снова стал коллекцией (String: BidirectionalCollection). Свойство characters удалено.

Что это означает на практике? Вы можете использовать большинство методов и свойств, характерных для коллекций, напрямую со строками:

let greeting = "Hello, Swift!"

// Свойства коллекции
print(greeting.count)           // 13 (количество Character)
print(greeting.isEmpty)         // false
print(greeting.first)           // Optional("H")
print(greeting.last)            // Optional("!")

// Итерация
for character in greeting.prefix(5) {
    print(character) // H, e, l, l, o
}

// Методы высшего порядка
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
let consonantCount = greeting.filter { !vowels.contains($0.lowercased()) }.count
print(consonantCount) // Пример подсчета согласных

// Индексация (осторожно, String — не RandomAccessCollection)
let index = greeting.index(greeting.startIndex, offsetBy: 7)
print(greeting[index]) // "S"

Важное предупреждение о производительности: String является коллекцией Character, а Character может состоять из нескольких Unicode scalar values. Из-за этой сложности:

  • String соответствует BidirectionalCollection, но НЕ RandomAccessCollection. Это значит, что доступ по произвольному индексу (например, greeting[5]) невозможен напрямую — нужно использовать String.Index.
  • Операция count имеет сложность O(n), так как требует подсчета всех графемовых кластеров.
// ❌ Не скомпилируется
// let fifthChar = greeting[5]

// ✅ Правильный способ доступа по индексу
let stringIndex = greeting.index(greeting.startIndex, offsetBy: 5)
let fifthChar = greeting[stringIndex] // ","

Вывод: String — это специализированная коллекция символов (Character), поддерживающая большинство операций коллекций, но с особенностями индексации, связанными с корректной обработкой Unicode.