generic์ ๋ณด๋ฉด์ ๋ช๋ช ๊ณณ์์ where
ํค์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณด์๋ค. ํ๋ฒ ์ ๋ฆฌํด์ผ ํ ๊ฒ ๊ฐ์ ๊ณต์ ๋ฌธ์์ ์ฝ์ด๋ณธ๋ค.
Generic Where Clauses
generic์๋ where
์กฐํญ์ ๋ฃ์ด ๋ฐ๋ ํ์
์ ์ธ๋ถ ์ ์ฝ์ ์ถ๊ฐํ ์ ์๋ค.
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
// Check that both containers contain the same number of items.
if someContainer.count != anotherContainer.count {
return false
}
// Check each pair of items to see if they're equivalent.
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// All items match, so return true.
return true
}
extension Array: Container {} // ์ด๋ฏธ ํด๋น ๋ฉ์๋๋ฅผ ์ค์ํ๊ณ ์์
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
// Prints "All items match."
์ผ๋ฐ where
์ ์ where
ํค์๋๋ก ์์ํ ๋ค์, associated type์ ๋ํ ์ ์ฝ ์กฐ๊ฑด ๋๋ associated type ๊ฐ์ ๋๋ฑ ๊ด๊ณ ๋ฑ์ ์ ์ํ ์ ์๋ค. allItemsMatch
ํจ์๋ ๋๊ฐ์ Container ํ๋กํ ์ฝ์ ์ค์ํ๋ ๊ตฌํ์ฒด๋ฅผ ๋ฐ์ ๋ด์ฉ๋ฌผ์ด ๋ชจ๋ ๊ฐ์์ง ๋น๊ตํ๋ค. ์ด ๋, ๋๊ฐ์ Container์ associted type์ธ Item
ํ์
์ด ์๋ก ๊ฐ์์ง, ๊ทธ๋ฆฌ๊ณ Eqatable
ํ๋กํ ์ฝ์ ์ค์ํ๋์ง์ ๋ํ ์ ์ฝ์ ์ถ๊ฐํ๋ค. ์ด๋ฐ ๊ธฐ๋ฅ์ compile time์ ํ์
์ฒดํฌ๋ฅผ ํ ์ ์๊ธฐ ๋๋ฌธ์ type safeํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
Extensions with a Generic Where Clause
where
์ ์ extension์๋ ์ถ๊ฐํ ์ ์๋ค.
struct Stack<Element>: Container {
// original Stack<Element> implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(_ item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
์์ ๋จ์ํ stack์ ๊ฒฝ์ฐ์๋ element๊ฐ์ ๋๋ฑ ์ฌ๋ถ("=="
)๋ฅผ ํ์ธํ ์ ์์๋ค. ์ด๋ Item์ด Equable
protocol์ ์ค์ํ์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค. ์คํํ๋ฉด compile error๊ฐ ๋จ๊ฒ ๋ ๊ฒ์ด๋ค. ์ด๋ฐ ๊ฒฝ์ฐ, ๋ถ๋ถ์ ์ผ๋ก extension์ Item type์ where
๋ฅผ ํตํ ์ ์ฝ์ ๊ฑธ์ด ๋ถ๋ถ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
if stackOfStrings.isTop("tres") {
print("Top element is tres.")
} else {
print("Top element is something else.")
}
// Prints "Top element is tres."
๋ง์ฝ equtable์ ์ค์ํ๊ณ ์์ง ์์ ํ์ ์ผ๋ก ๋ง๋ค๋ฉด ์ด๋จ๊น?
struct NotEquatable { }
var notEquatableStack = Stack<NotEquatable>()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
notEquatableStack.isTop(notEquatableValue) // Error
๋น์ฐํ๊ฒ๋ compile error๊ฐ ๋ฌ๋ค.
Extension with a Protocol where clause
์ด๋ ๊ฒ extension์ where
์ ์ฌ์ฉํด์ ์ถ๊ฐ์ ์ธ ์ ์ฝ์ ๊ฑฐ๋ ๊ฒ์ protocol์์๋ ๊ฐ๋ฅํ๋ค.
extension Container where Item: Equatable {
func startsWith(_ item: Item) -> Bool {
return count >= 1 && self[0] == item
}
}
extension Container where Item == Double {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += self[index]
}
return sum / Double(count)
}
}
if [9, 9, 9].startsWith(42) {
print("Starts with 42.")
} else {
print("Starts with something else.")
}
// Prints "Starts with something else."
print([1260.0, 1200.0, 98.6, 37.0].average())
// Prints "648.9"
protocol์ extension์ ๊ธฐ๋ณธ ๋์์ ์ ์ํ ์ ์๋๋ฐ, ์ด๊ฒฝ์ฐ where์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์ถ๊ฐ์ ์ธ ์ ์ฝ์ ๊ฑธ๋ฉด์ ๊ธฐ๋ณธ๋์๊น์ง ์ฒ๋ฆฌํ ์ ์๋ค. ([9, 9, 9]
๊ฐ ์ฒ๋ฆฌ๊ฐ๋ฅ ํ ๊ฒ์ ์์์ extension Array: Container {}
๋ฅผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.)