let str = "Hello, Swift"
let l = str.lowercased()
// Substring -> 하나의 문자열에서 특정 범위에 있는 문자열
var first = str.prefix(1)
// 왜 사용할까?
// 문자열을 처리할때 메모리 낭비를 줄이기 위해서
// --> Substring은 원본 문자열의 메모리를 공유한다
// Substring은 값을 읽기만 할때는 원본 메모리를 공유하고 값을 변경할때는 새로운 메모리를 할당받는다.
// 이 시점에 새로운 메모리를 생성
first.insert("!", at: first.endIndex)
// 이런걸 Copy-on-Write Optomizaition 이라고 부른다.
str
first
// Copy-on-Write Optomizaition 을 사용하지 않고 Substring을 새로운 문자열로 바로 생성하고 싶으면?
// 요롷게 하면 된다.
let newStr = String(str.prefix(1))
// 문자열에서 특정 범위 추출
// 빨간줄 메소드는 deprecated 메소드다.
//str.substring(to: str.index(str.startIndex, offsetBy: 2))
let s = str[str.startIndex ..< str.index(str.startIndex, offsetBy: 2)]
// 흠 근데 코드가 너무 길다?
// 그러면 one sided range 사용
let s2 = str[..<str.index(str.startIndex, offsetBy: 2)]
str[str.index(str.startIndex, offsetBy: 2)...]
// 근데 중간 값을 가져오고 싶을때는 one sided range를 사용할 수 없음
let lower = str.index(str.startIndex, offsetBy: 2)
let upper = str.index(str.startIndex, offsetBy: 5)
str[lower ... upper]