문자열에서 서브스크립토 또는 prefix(_:)과 같은 메소드를 사용하여 부분 문자열을 얻을 때 그 결과는 다른 문자열이 아닌 Substring의 인스턴스이다.
Swift의 부분 문자열은 문자열과 거의 동일한 메소드를 가지고 있기 때문에 문자열과 동일하게 부분 문자열을 사용할 수 있다.
그러나 문자열과 다르게 문자열에 대한 작업을 수행하는 동안 짧은 시간동안만 부분 문자열을 사용한다.
결과를 저장할 준비가 되었을 때 부분 문자열을 String의 인스턴스로 변환한다.
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"
// Convert the result to a String for long-term storage.
let newString = String(beginning)
문자열과 마찬가지로 각 부분 문자열에는 부분 문자열을 구성하는 문자가 저장되는 메모리 영역이 있다.
문자열과 부분 문자열의 차이점은 성능 최적화를 위해 부분 문자열이 원래 문자열을 저장하는 데 사용된 메모리의 일부 또는 다른 부분 문자열을 저장하는 데 사용되는 메모리의 일부를 재사용할 수 있다는 것이다.
(문자열은 비슷한 최적화를 갖지만 두 문자열이 메모리를 공유하면 두 문자열은 같다.)
이 성능 최적화는 문자열이나 부분 문자열을 수정할 때까지 메모리 복사에 대한 비용을 지불한 필요가 없음을 의미한다.
위에서 언급했듯이 부분 문자열은 장기 저장에 적합하지 않다.
그 이유는 부분 문자열은 원래 문자열의 저장소를 재사용하기 때문에 부분 문자열이 사용되는 한 전체 원본 문자열을 메모리에 저장해야 하기 때문이다.
위의 예제에서 greeting은 문자열을 구성하는 문자가 저장되는 메모리 영역이 있는 문자열이다.
beginning은 greeting의 부분 문자열이기 때문에 greeting이 사용하는 메모리를 재사용한다.
반대로 newString은 문자열이다. 부분 문자열에서 생성될 때 자신만의 저장소를 가진다.

Note:
String과 Substring은 모두 StringProtocol을 준수한다.
이것은 문자열 조작 함수가 StringProtocol 값을 받아들이는 것이 편리한 경우가 많다는 것을 의미한다.
이러한 함수는 String 또는 Substring 값으로 호출할 수 있다.