Semantics Type
typealias Kilograms = Double
struct Package {
var weight: Kilograms
}
Combine Protocols
protocol ReadAccess {}
protocol WriteAccess {}
typealias AdminAccess = ReadAccess & WriteAccess
struct Teacher: AdminAccess {}
Int
, Double
์ ์ด๋์๋ ์ฌ์ฉ๋๋ ํ์
์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฝ๋ ์์ฑ์ ์ด๋ค ์๋ฏธ๋ก ํด๋น ํ์
์ ์ฌ์ฉํ๋์ง๋ ์ฝ๋๋ฅผ ์ฝ์ด๋ด์ผ ์ ์ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ์๋ฏธ๋ก ์ ์ธ ํ์
์ ์ ์ธํ๊ธฐ ์ํด ํ์ฉํ ์ ์๋ค.
Specializing generics
Type alias๋ฅผ ํ์ฉํ๋ ๋ค์ ๋ฐฉ๋ฒ์, ์ฝ๋ ์ ๋ฐ์ ๊ฑธ์ณ, ๊ฐ์ generic type์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ด๋ค. ์ฆ, ๊ฐ์ generic์ ์ฌ์ฉํ๋๋ฐ, ์ด generic์ด ๊ธธ์ด์ง๋ ๋ฑ์ ์ด์ ๋ก ์คํ๋ ค ์ด๋ค ์๋ฏธ์ธ์ง ํ์ ํ๊ธฐ ์ด๋ ต๋ค๋ฉด ์ฌ์ฉํ์. ์๋ฅผ ๋ค์ด, Note App์ ๋ง๋๋๋ฐ, ๊ทธ ์์ storage type์ ๋ฐ์ํ์ผ ํ๋ ์ํฉ์ ์๊ฐํด๋ณด์.
class FileStorage<Key: Hashable, Location: FileStorageLocation> {
...
}
class NoteSyncController {
init(localStorage: FileStorage<Note.StorageKey, LocalFileStorageLocation>,
cloudStorage: FileStorage<Note.StorageKey, CloudStorageLocation>) {
...
}
}
์๋นํ ์ฝ๊ธฐ ์ด๋ ต๋ค. ์ฌ๊ธฐ์ ํ๋ฒ์ ์ถ์ํ๋ฅผ ํ๋ค๋ฉด ๊ฐ๋
์ฑ์ด ํฌ๊ฒ ํฅ์๋ ๊ฒ์ด๋ค. ์ฐธ, Key: Hashable
๊ณผ ๊ฐ์ด ๋์ด ์๋ ๊ฒ์ generic์์ type constraints๋ผ๊ณ ํ๋ค. ํด๋น Type๋ง ์ฌ์ฉํ๋๋ก ์ ์ฝํ๋ ๊ฒ์ด๋ค. ์์ธํ ๋ด์ฉ์ ๋ค์๊ธ์์ ์์๋ณด์.
class FileStorage<Key: Hashable, Location: FileStorageLocation> {
...
}
// Model
extension Note {
typealias LocalStorage = FileStorage<StorageKey, LocalFileStorageLocation>
typealias CloudStorage = FileStorage<StorageKey, CloudStorageLocation>
}
class NoteSyncController {
init(localStorage: Note.LocalStorage,
cloudStorage: Note.CloudStorage) {
...
}
}
Note model์์ type alias๋ฅผ ๋์ด ์ฌ์ฉํ๋ ์ธก์์ ๊ฐ๋ณ๊ฒ ์ธ ์ ์๋๋ก ํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด, ๊ตฌํ์ ์ธ๋ถ์ฌํญ ์ญ์ Model ๋ด๋ถ๋ก ์จ๊ธธ ์ ์๋ค.
Type-driven Logic
๊ฐ๊ฐ์ object์ ๋ํ id๋ฅผ ์ ๋ฐ์์ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ ๋ค๊ณ ํด๋ณด์. id์ ํน์ง์ Identifiable
Protocol์ ์ ์ํ๊ณ , ์ด๋ฅผ ๊ตฌํ์ฒด๊ฐ ์ด๋ฅผ ์ฑํํจ์ผ๋ก์จ ๊ฐ๋ฅํ๊ฒ ํด๋ณด์. ๊ทธ๋ฐ๋ฐ ์ด ๋, id๋ฅผ ํ์ํ๊ธฐ ์ํด์๋ ์ด๋ฅผ ๋ํํ๋ ๊ฐ์ ๊ฐ์ ธ์ผ ํ๋ค. ์ด๋ด ๋ associatedType
์ ํ์ฉํด์ ์ด๋ฅผ ์ ์ํ๋ค.
protocol Identifiable {
associatedtype RawIdentifier: Codable = String
var id: Identifier<Self> { get }
}
๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ค์ํ๋ ๊ตฌํ์ฒด๋ฅผ ๋ฐ๋ struct๋ฅผ ๋ง๋ค์.
struct Identifier<Value: Identifiable> {
let rawValue: Value.RawIdentifier
init(rawValue: Value.RawIdentifier) {
self.rawValue = rawValue
}
}
Identifier
๊ตฌํ์ฒด๋ Identifiable์ ์ค์ํ๋ ๊ตฌํ์ฒด๋ฅผ rawvalue๋ก ๊ฐ์ง๋ค.
struct User: Identifiable {
let id: Identifier<User>
let name: String
}
struct Group: Identifiable {
typealias RawIdentifier = Int
let id: Identifier<Group>
let name: String
}
let group = Group(id: Identifier<Group>(rawValue: 3), name: "wansik")
Identifiable
์ ์ค์ํ๋ ๋๊ฐ์ struct๋ฅผ ๋ง๋ค์๋ค. ์ด ๋, User
์ ๊ฒฝ์ฐ ๋ช
์ํ์ง ์์๊ธฐ ๋๋ฌธ์ RawIdentifier๊ฐ String
์ผ๋ก ๋ฐ์๋๊ณ , Group
์ ๊ฒฝ์ฐ ๋ช
์ํ์ฌ ๋ณ๊ฒฝํ ์ ์๋ค. ์ฆ, Protocol์ด associatedType์ผ๋ก type constraint๊ฐ ๋์ด ์๋ ๊ฒฝ์ฐ, ์ด๋ฅผ ๋ช
์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก type alias๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ถ๊ฐ์ ์ผ๋ก, ์์ ๊ฐ์ ํ์์ผ๋ก ๊ตฌํํ ๊ฒฝ์ฐ, id๋ฅผ type safeํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
Generic Closures
typealias Handler<T> = (Result<T>) -> Void
func searchForNotes(matching query: String,
then handler: @escaping Handler<[Note]>) {
...
}
๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๋ completion Handler๋ฅผ type alias๋ก ์ฒ๋ฆฌํ ์ ์๋ค. ์กฐ๊ธ๋ ์๋ฏธ์๋ ์ ๋ณด๋ฅผ ์ค ์ ์๋ค. ์คํจ์, ์ฑ๊ณต์ ๊ฐ๊ฐ์ handler๋ฅผ ์ด๋ฐ์์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ๋ ์ฝ๊ธฐ ์ข์ ์ฝ๋๋ฅผ ๋ง๋ค ์ ์๊ฒ ๋ค.