Swift의 String은 Struct타입이고, characters
의 collection이다. 즉 Array<Element
>의 element가 Character인 배열이다.
하지만 Swift에서 String은 subscript, 즉 str[0]같이 Int로 접근하지 못하고, String.index로 접근해야한다.
그 이유는 Swift에서 Character는 1개 이상의 Unicode Scalar로 이루어져 있다. 즉 크기가 가변적이다. 아래와 같이 하나의 이모티콘은 여러개의 unicodeScalars로 이루어져 있는 것을 확인할 수 있다.
let testString = "👩👩👧👦"
print("------> testString")
testString.forEach { char in
print(type(of: char))
}
print("------> testString.utf8")
testString.utf8.forEach {
print(type(of: $0), $0)
}
print("------> testString.utf16")
testString.utf16.forEach {
print(type(of: $0), $0)
}
print("------> testString.unicodeScalars")
testString.unicodeScalars.forEach {
print(type(of: $0), $0)
}
따라서 String은 subscript를 Int가 아니라 String.Index를 통하여 값을 확인할 수 있다.
String은 Collection에서 O(1)로 접근할 수 있는 RandomAccessCollection프로토콜을 준수하지 않고, 앞 뒤의 원소만 참조할 수 있는 BidirectionalCollection을 준수한다.
이 때문에 String.count의 시간복잡도는 O(n)이 된다. 또한 String.Index는 +,-연산을 지원하지 않기 때문에 현재 인덱스에서 n 만큼 떨어진 글자를 참조하기 위해서는 O(n)의 시간복잡도가 필요하다.
따라서 알고리즘 문제를 풀 때 같은 경우에는 Array(str)을 통해 명시적으로 [Character] 형태로 반환하는 것이 효율적이다.