ํจ์๋ ๋ฉ์๋์์ opaque return type์ ์ฌ์ฉํ๋ค๋ฉด ๋ฆฌํด ๊ฐ์ ํ์ ์ ๋ณด๋ฅผ ์จ๊ธธ ์ ์์ต๋๋ค. ํจ์์ ๋ฆฌํดํ์ ์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๋ช ์ํ๋ ๋์ ํด๋น ํ์ ์ด ๋ฐ๋ฅด๋ ํ๋กํ ์ฝ์ ๋ช ์ํฉ๋๋ค. ๋ฆฌํดํ์ ์ ์จ๊ธฐ๋ ๊ฒ์ ๋ชจ๋๊ณผ ๋ชจ๋์ ํธ์ถํ๋ ์ฝ๋ ์ฌ์ด์์ ํด๋น ๋ฆฌํด ๊ฐ์ private ํ๊ฒ ๋ ์ ์์ต๋๋ค. ๋ฆฌํดํ์ ์ ํ๋กํ ์ฝ ํ์ ์ผ๋ก ์ค์ ํ๋ ๊ฒ๊ณผ๋ ๋ฌ๋ฆฌ opque type์ ํ์ ์ identity๋ฅผ ์ ์งํฉ๋๋ค.(module์ ํด๋ผ์ด์ธํธ๋ ์ ๊ทผํ ์ ์์ง๋ง ์ปดํ์ผ๋ฌ๋ ํ์ ์ ๋ณด์ ์ ๊ทผํ ์ ์์ต๋๋ค.)
์๋ฅผ ๋ค์ด, ์์คํค ์ฝ๋๋ก ๋ํ์ ๋ง๋๋ ๋ชจ๋์ ์ฝ๋ฉํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์์คํค ๋ํ ์๋ draw()ํจ์๊ฐ ์์ด์ ๋ํ์ ๋ชจ์์ string์ผ๋ก ๋ฆฌํดํด์ค๋๋ค. ์ด๋ Shape ํ๋กํ ์ฝ์ ๋ช ์๋์ด ์์ต๋๋ค.
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result: [String] = []
for length in 1...size {
result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}
let smallTriangle = Triangle(size: 3)
print(smallTriangle.draw())
// *
// **
// ***
์๋์ ๊ฐ์ด ์ ๋ค๋ฆญ์ ์ด์ฉํ์ฌ ๋ํ์ ์ ์๋๋ก ๋ค์ง์ ์ ์๋ ์ฝ๋๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ํ์ง๋ง ์ด๋ฐ ์ ๊ทผ ๋ฐฉ์์๋ ์ค๋ํ ์ ์ฝ์ด ์๋ค. flipped result๊ฐ ๋ง๋ค์ด์ง ๋ ์ ๋ค๋ฆญ์ด ๋ ธ์ถ๋ ์ ๋ฐ์ ์๋ค. However, thereโs an important limitation to this approach: The flipped result exposes the exact generic types that were used to create it. (์ธ์๋ก ํ์ ์ ๋ฃ์ด์ค์ ๊ทธ๋ฐ๊ฑด๊ฐ? opaque๋ ์๊ทธ๋ฐ๊ฐ?)
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
let flippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle.draw())
// ***
// **
// *
(์ด ๋ฐฉ๋ฒ์ ์๋์ฒ๋ผ ์ฌ๋ฌ๊ฐ๋ฅผ ์ค์ฒฉํด์ ์ธ ๋ ์ ๋ค๋ฆญ์ด ์์ฒญ ๋ง์์ง๋ค๋ ๋จ์ ์ด ์๋๋ฏํ๋ค)
์๋์ JoinedShape<T: Shape, U: Shape>
๋ฅผ ํตํด 2๊ฐ์ shape๋ฅผ ํฉ์น ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, flipped triangle๊ณผ ๋ค๋ฅธ triangle์ ํฉ์น๋ค๋ฉด JoinedShape<FlippedShape<Triangle>, Triangle>
์ฒ๋ผ ํํํ ์ ์์ต๋๋ค.
This approach to defining a JoinedShape<T: Shape, U: Shape>
structure that joins two shapes together vertically, like the code below shows, results in types like JoinedShape<FlippedShape<Triangle>, Triangle>
from joining a flipped triangle with another triangle.
struct JoinedShape<T: Shape, U: Shape>: Shape {
var top: T
var bottom: U
func draw() -> String {
return top.draw() + "\n" + bottom.draw()
}
}
let joinedTriangles = JoinedShape(top: smallTriangle, bottom: flippedTriangle)
print(joinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
๋ํ ์์ฑ์ ๋ํ ์์ธํ ์ ๋ณด๋ฅผ ๋ ธ์ถํ๋ฉด ์ ์ฒด ๋ฐํ ์ ํ์ ๋ช ์ํด์ผ ํ๋ฏ๋ก ASCII ์ํธ ๋ชจ๋์ public ์ธํฐํ์ด์ค์ ํฌํจ๋์ง ์๋ ์ ํ์ด ๋์ถ๋ ์ ์์ต๋๋ค. ๋ชจ๋ ๋ด๋ถ์ ์ฝ๋๋ ๋ค์ํ ๋ฐฉ์์ผ๋ก ๋์ผํ ๋ชจ์์ ๋ง๋ค ์ ์์ผ๋ฉฐ, ๋ชจ์์ ์ฌ์ฉํ๋ ๋ชจ๋ ์ธ๋ถ์ ๋ค๋ฅธ ์ฝ๋๋ ๋ณํ ๋ชฉ๋ก์ ๋ํ ๊ตฌํ ์ธ๋ถ ์ ๋ณด๋ฅผ ๊ณ ๋ คํ ํ์๊ฐ ์์ต๋๋ค. JoinedShape๋ FlippedShape์ ๊ฐ์ Wrapper type๋ค์ module ์ฌ์ฉ์์๊ฒ ์ค์ํ์ง ์์ผ๋ฉด ๋ณด์ด์ง ์์์ผ ํฉ๋๋ค. ๋ชจ๋์ public interface์ join๊ณผ flip์ ๊ฐ์ ๋์๋ค๋ก ๊ตฌ์ฑ๋์ด์ผ ํ๊ณ ์ด ๋์๋ค์ ๋ ๋ค๋ฅธ Shapeํ์ ์ ๋ฆฌํดํด์ผ ํ๋ค.
opaque type์ ์ ๋ค๋ฆญ์ reverse ๋ฒ์ ์ด๋ผ๊ณ ์๊ฐํ ์ ์๋ค. ์ ๋ค๋ฆญ ํ์ ๋ค์ ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋๊ฐ ํด๋น ํจ์์ ๋งค๊ฐ ๋ณ์์ ๋ํ ํ์ ์ ์ ํํ๊ณ ํจ์ ๊ตฌํ์์ ์ถ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ฐ์ ๋ฐํํ๋๋ก ํฉ๋๋ค. ์๋ฅผ๋ค์ด, ์๋ ํจ์์ ๋ฆฌํด๊ฐ์ ๋ค์ด์ค๋ ์ธ์์ ๋ฌ๋ ค์์ต๋๋ค.
func max<T>(_ x: T, _ y: T) -> T where T: Comparable { ... }
max(::)ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋์์ x์ y๊ฐ์ ๊ณ ๋ฅด๋ฉด T์ ํด๋นํ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ด ๊ฒฐ์ ๋๋ค. ํธ์ถํ๋์ชฝ์์๋ Comparable์ ๋ฐ๋ฅด๋ ์ด๋ค ํ์ ๋ ์ฌ์ฉํ ์ ์๋ค. ํจ์ ๋ด๋ถ์์๋ generalํ๊ฒ ์ฝ๋๊ฐ ์์ฑ๋์ด์ ๋๊ฒจ์ฃผ๋ ์ชฝ์์ ์ด๋ค ํ์ ์ ๋๊ฒจ์ฃผ์ด๋ ๋์ํ ์ ์๋ค. max(::)์ ๊ตฌํ์ ๋ชจ๋ Comparable ํ์ ์ด ๊ฐ๊ณ ์๋ ํ์ ๋ค์ ๊ธฐ๋ฅ๋ง์ ์ฌ์ฉํ๋ค.
์ด๋ฐ ์ญํ ๋ค์ opaque return type์์ reverse๋์ด์ง๋ค. An opaque type lets the function implementation pick the type for the value it returns in a way thatโs abstracted away from the code that calls the function. ์๋ฅผ ๋ค์ด, ์๋ ํจ์๋ ์ฌ๋ค๋ฆฌ๊ผด(trapezoid)๋ฅผ ๋ฆฌํดํ๋๋ฐ ๋ฆฌํด๊ฐ์ด ์ด๋ค ํ์ ์ธ์ง ๋ ธ์ถ๋์ง ์์ต๋๋ค.
struct Square: Shape {
var size: Int
func draw() -> String {
let line = String(repeating: "*", count: size)
let result = Array<String>(repeating: line, count: size)
return result.joined(separator: "\n")
}
}
func makeTrapezoid() -> some Shape {
let top = Triangle(size: 2)
let middle = Square(size: 2)
let bottom = FlippedShape(shape: top)
let trapezoid = JoinedShape(
top: top,
bottom: JoinedShape(top: middle, bottom: bottom)
)
return trapezoid
}
let trapezoid = makeTrapezoid()
print(trapezoid.draw())
// *
// **
// **
// **
// **
// *
makeTrapezoid() ํจ์์ ๋ฆฌํดํ์ some Shape์ด๋ค. ์ด๋ก์ธํด, return ํ์ ์ ํน์ ๊ตฌ์ฒด ํ์ ์ด ์๋ Shape protocol์ ๋ฐ๋ฅด๋ ํ์ ์ด๋ค. ๋ฐ๋ผ์ public interface์ ํ์ํ ์ค์ ์ ๋ณด๋ง์ ๋ ธ์ถ์ํค๊ณ ํน์ ํ์ ์ ๋ํ ์ ๋ณด๋ฅผ ๋ ธ์ถ์ํค์ง ์๋๋ค. ์ด ๊ตฌํ์ 2๊ฐ์ ์ผ๊ฐํ๊ณผ 1๊ฐ์ ์ฌ๊ฐํ์ ์ด์ฉํ๋ค. ํ์ง๋ง ํจ์๋ ๋ฆฌํดํ์ ์ ๋ฐ๊พธ์ง ์๊ณ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํ์ด ๋ฐ๋ ์ ์๋ค.
์ด ์๋ opaque return type์ด ์ ๋ค๋ฆญ์ reverseํ๋ค๋ ๊ฒ์ ๋ณด์ฌ์ค๋ค. makeTrapezoid()๋ SHape ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ์ด๋ค ๋ฆฌํดํ์ ๋ ๋ฆฌํดํ ์ ์๋ค. ์ด๊ฒ์ ๋ง์น ์ ๋ค๋ฆญํจ์๋ฅผ ํธ์ถํ๋ ๋ถ๋ถ๊ณผ ๋น์ทํ๋ค. ์ ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ generalํ๊ฒ ์ฐ์ฌ์ ธ์ผ ํ๋ค.(๋ง์น generic ํจ์์ ๊ตฌํ๋ถ์ฒ๋ผ) ๊ทธ๋์ ๋ค๋ฅธ ์ด๋ค Shape ๊ฐ๊ณผ๋ ์ํธ์์ฉํ ์ ์๋ค.
๋ํ ์๋ ํจ์์ฒ๋ผ opaque return type๊ณผ generic์ ๊ฐ์ด ์ธ ์๋ ์๋ค.
์ ๋ค๋ฆญ์ ํจ์์ ์์์ generalํ๊ฒ ๋ง๋ ๋ค๋ฉด opaque return type์ ํจ์์ ๋์ generalํ๊ฒ ๋ง๋๋ ๊ฒ ๊ฐ๋ค.
func flip<T: Shape>(_ shape: T) -> some Shape {
return FlippedShape(shape: shape)
}
func join<T: Shape, U: Shape>(_ top: T, _ bottom: U) -> some Shape {
JoinedShape(top: top, bottom: bottom)
}
let opaqueJoinedTriangles = join(smallTriangle, flip(smallTriangle))
print(opaqueJoinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
์ด ์์ ์ opaqueJoinedTriangles๋ ์์ joinedTriangles์ ๊ฐ์ ์ญํ ์ ํ๋ค. ๊ทธ๋ฌ๋ ์์ ์์ ์๋ ๋ฌ๋ฆฌ flip(:)๊ณผ join(:_:)์ ํด๋น ํ์ ์ ํ๋ฒ ๊ฐ์ธ์ opaque return type์ผ๋ก ๋ฆฌํดํ๋ค. ๋ฐ๋ผ์ ์ค๊ฐ์ ๋ฑ์ฅํ๋ ํ์ ์ ๋ณด์ด์ง ์๊ฒ ํด์ค๋ค. ๋ ํจ์ ๋ชจ๋ ์ ๋ค๋ฆญ ํจ์์ธ๋ฐ ํ์ ํ๋ผ๋ฏธํฐ๋ ํด๋น ์ ๋ณด๋ฅผ ํ์๋ก ํ๋ FlippedShape์ JoinedShape์๊ฒ ์ ๋ฌ๋๋ค.
๋ง์ฝ opaque return type์ ๊ฐ๊ณ ์๋ ํจ์๊ฐ ๋ฆฌํดํ๋ ๋ถ๋ถ์ด ์ฌ๋ฌ๊ณณ์ ์๋ค๋ฉด, ํญ์ ๊ฐ์ ํ์ ์ ๋ฆฌํดํด์ผํ๋ค. ์ ๋ค๋ฆญ ํจ์์ ๊ฒฝ์ฐ ๋ฆฌํดํ์ ์ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ ์ ์์ง๋ง ๋ชจ๋ ๊ฐ์ ํ์ ์ด์ด์ผ ํ๋ค. ์๋ฅผ๋ค์ด ์๋์ ๊ฐ์ ํจ์๋ ์๋ฌ๋ฅผ ๋์ง๋ค.
func invalidFlip<T: Shape>(_ shape: T) -> some Shape {
if shape is Square {
return shape // Error: return types don't match
}
return FlippedShape(shape: shape) // Error: return types don't match
}
์๋ฌ๋ฅผ ์๋๊ฒ ํ๋ ค๋ฉด ์๋์ฒ๋ผ FlippedShape๋ฅผ ์์ ํ๋ฉด ๋๋ค.
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
if shape is Square {
return shape.draw()
}
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
ํญ์ ๊ฐ์ ํ์ ์ ๋ฆฌํดํด์ผ ํ๋ค๊ณ ํด์ opaque return type์ด ์ ๋ค๋ฆญ์ ์ฌ์ฉํ์ง ๋ชปํ๋ ๊ฒ์ด ์๋๋ค. Hereโs an example of a function that incorporates its type parameter into the underlying type of the value it returns:
func `repeat`<T: Shape>(shape: T, count: Int) -> some Collection {
return Array<T>(repeating: shape, count: count)
}
[T]๊ฐ ํญ์ ๋ค๋ฅธ ํ์ ์ผ ์ ์์ง๋ง some Collection์ ํตํด ํ๋์ ํ์ ์ผ๋ก ๋ฆฌํดํ ์ ์๋ค.
In this case, the underlying type of the return value varies depending on T: Whatever shape is passed it, repeat(shape:count:) creates and returns an array of that shape. Nevertheless, the return value always has the same underlying type of [T], so it follows the requirement that functions with opaque return types must return values of only a single type.
opaque type์ผ๋ก ๋ฆฌํดํ๋ ๊ฒ์ protocol type์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋งค์ฐ ๋น์ทํฉ๋๋ค. ์ด 2๋ฐฉ์์ ์ฐจ์ด์ ์ ํ์ ์ identity๋ฅผ ๋ณด์กดํ๋ ์ง์ด๋ค. opaque type์ ํน์ ํ์ ์ ์๋ ค์ค๋ค. ๋น๋ก ์ด opaque return type์ ๊ฐ๊ณ ์๋ ํจ์๋ฅผ ํธ์ถํ๋ ์ชฝ์์๋ ๋ณผ ์ ์๋ค. ๋ฐ๋ฉด protocol type์ ํด๋น protocol์ ๋ฐ๋ฅด๋ ์ด๋ ํ ํ์ ๋ ๊ฐ๋ฆฌํฌ ์ ์๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋งํด์ protocol type์ ๋ ์ ์ฐํ๊ฒ ์ฌ๋ฌ ํ์ ๋ค์ ์ ์ฅํ ์ ์๊ณ opaque type์ ํน์ ํ์ ์ ๊ฐ๊ฒ ํด์ค๋ค.
์๋ฅผ ๋ค์ด, ์๋ ํจ์์์ opaque type ๋์ protocol type์ ๋ฆฌํดํ๋ค.
func protoFlip<T: Shape>(_ shape: T) -> Shape {
return FlippedShape(shape: shape)
}
์ฌ๊ธฐ protoFlip๊ณผ ์์ flip์ ๊ฐ์ ๋ฐ๋๋ฅผ ๊ฐ๊ณ ์๊ณ ๋๊ฐ์ ํ์ ์ ๋ฆฌํดํ๋ค. flip๊ณผ๋ ๋ฌ๋ฆฌ protoType์ Shape ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ๊ทธ ์ด๋ค๊ฒ๋ ๋ฆฌํดํ ์ ์๋ค. protoFlip์ flip๋ณด๋ค ๋ ๋์จํ๊ฒ API ์ํธ์์ฉ์ ํ๊ฒ ๋๋ค. ์ฌ๋ฌ ํ์ ์ ๋ฆฌํดํ ์ ์๋ ์ ์ฐ์ฑ์ ๊ฐ๊ฒ ๋๋ค.
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
์ด ๋ฒ์ ์ Square๋ FlippedShape๋ฅผ ๋ฆฌํดํ ์ ์๋๋ฐ ์ด๋ ์ด๋ค ๋ํ์ด ์ธ์๋ก ๋ค์ด์ค๋์ง์ ๋ฌ๋ ธ๋ค. ์ด ํจ์๋ฅผ ํตํด ๋ง๋ค์ด์ง 2๊ฐ์ flipped shape๋ ์์ ํ ๋ค๋ฅธ ํ์ ์ด ๋ ์๋ ์๋ค. protoFlip์์์ฒ๋ผ ๋ ์ ์ ์ ๋ณด๋ฅผ ๋ฆฌํดํ๋ ๊ฒ์ ํ์ ์ ๋ณด์ ๋ฐ๋ผ ๋์ํ๋ ์ฌ๋ฌ ๊ธฐ๋ฅ๋ค์ ์ฌ์ฉํ ์ ์์์ ์๋ฏธํ๋ค. ์๋ฅผ ๋ค์ด ์๋ == operator๋ ์ฌ์ฉํ ์ ์๋ค.
let protoFlippedTriangle = protoFlip(smallTriangle)
let sameThing = protoFlip(smallTriangle)
protoFlippedTriangle == sameThing // Error
๋ง์ง๋ง ์ค์ ์๋ฌ๋ ๋ช๊ฐ์ง ์ด์ ๋๋ฌธ์ด๋ค. Shape ํ๋กํ ์ฝ์๋ == operator๊ฐ ๋ช ์๋์ง ์์๋ค. == operator๋ฅผ ์ถ๊ฐํ๋ ค๊ณ ํ๋ค๋ฉด ๋ ๋ค๋ฅธ ๋ฌธ์ ๋ฅผ ๋ง๋๊ฒ ๋๋๋ฐ ์ด๋ lhs์ rhs์ ํ์ ์ ์์์ผ ํ๋ค. ์ด๋ฐ ์ข ๋ฅ์ operator๋ Self ํ์ ์ ์ธ์๋ก ๋ฐ๋ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์๋ค. ์ด Self๋ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ๊ตฌ์ฒด ํ์ ๊ณผ ๋งค์นญ๋๋ค.
ํ๋กํ ์ฝ ํ์ ์ ๋ฆฌํดํ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ํด๋น ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ์ด๋ค ํ์ ๋ ๋ฆฌํดํ์ ์ด ๋ ์ ์๋ ์ ์ฐํจ์ ์ ๊ณตํ๋ค. ๊ทธ๋ฌ๋ ๊ทธ ์ ์ฐํจ์ ๋๊ฐ๋ก ๋ฆฌํด ํ์ ์ ํน์ ๊ธฐ๋ฅ๋ค์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. ์ด ์๋ฅผ ์ด๋ป๊ฒ == operator๊ฐ ์ฌ์ฉ๋์ง ๋ชปํ๋์ง๋ฅผ ๋ณด์ฌ์ค๋ค. ์ด๋ ํ๋กํ ์ฝ ํ์ ์ ์ํด ๋ณด์กด๋์ง ์๋ ํน์ ํ์ ์ ๋ณด์ ๋ฌ๋ ค์๋ค.(ํ๋กํ ์ฝ์ ๋ช ์๋์ง ์์ผ๋ฉด ๋ชป์ด๋ค.)
์ด ํ๋กํ ์ฝ ํ์ ๋ฐฉ์์ ๋ ๋ค๋ฅธ ๋ฌธ์ ๋ shape์ ๋ณํ์ด ์ค์ฒฉ๋์ง ์๋๋ค. ์ผ๊ฐํ์ flipping ๊ฒฐ๊ณผ๋ Shape ํ์ ์ด๋ค. ๊ทธ๋ฆฌ๊ณ protoFlip์ Shape protocol์ ๋ฐ๋ฅด๋ ํ์ ์ ์ธ์๋ก ๋ฐ์ ์ ์๋ค. ๊ทธ๋ฌ๋, ํ๋กํ ์ฝ ํ์ ์ ๊ฐ์ protocol์ ๋ฐ๋ฅด์ง ์๋๋ค. ์ฆ protoFlip์ ๋ฆฌํด๊ฐ์ Shape protocol์ ๋ฐ๋ฅด์ง ์๋๋ค. ์ด ๋ง์ protoFlip(protoFlip(smallTriangle))๊ณผ ๊ฐ์ ์ค์ฒฉ ๋ณํ์ด ๋ถ๊ฐ๋ฅํ๋ค.
์ด์๋ ๋ฌ๋ฆฌ opaque type์ ํด๋น ํ์ ์ identity๋ฅผ ๋ณด์กดํ๋ค. ์ค์ํํธ๋ associated types์ ์ถ๋ก ํ ์ ์๋๋ฐ ์ด๋ก์จ opaque return value๋ฅผ ๋ฆฌํด ๊ฐ์ผ๋ก ์ง์ ํ ์ ์๋ค.(ํ๋กํ ์ฝ ํ์ ์ ๋ถ๊ฐ๋ฅํ๋ฐ ๋ฐํด)
protocol Container {
associatedtype Item
var count: Int { get }
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
Container๋ฅผ ํจ์์ ๋ฆฌํดํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. ์๋ํ๋ฉด ํ๋กํ ์ฝ์ associatedtype์ ๊ฐ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
// Error: Protocol with associated types can't be used as a return type.
func makeProtocolContainer<T>(item: T) -> Container {
return [item]
}
// Error: Not enough information to infer C.
func makeProtocolContainer<T, C: Container>(item: T) -> C {
return [item]
}
opaque type์ ๋ฆฌํด ํ์ ์ผ๋ก ์ฌ์ฉํจ์ผ๋ก์จ API์ ์๊ตฌํ๋๋๋ก ์์ฑํ ์ ์๋ค.
func makeOpaqueContainer<T>(item: T) -> some Container {
return [item]
}
let opaqueContainer = makeOpaqueContainer(item: 12)
let twelve = opaqueContainer[0]
print(type(of: twelve))
// Prints "Int"
twelve์ ํ์ ์ Int๊ฐ ๋๋ค. ์๋ํ๋ฉด opaque type์์๋ ํ์ ์ถ๋ก ์ด ์ผ์ด๋๊ธฐ ๋๋ฌธ์ด๋ค. makeOpaqueContainer(item:)์์ ํํ๋๋ opaque container๋ [T]์ด๋ค. ์ฌ๊ธฐ์ T๋ Int๊ฐ ๋๊ฒ ๋๋๋ฐ ๊ทธ๋ฆฌํ์ฌ Int๋ฐฐ์ด์ ๋ฆฌํดํ๊ณผ associated type์ธ Item์ ์๋ฃํ์ Int๋ก ์ถ๋ก ๋๋ค. Container์ subscript๋ Item์ ๋ฆฌํดํ๊ณ ์ด๋ Int๋ฅผ ์๋ฏธํ๋ค.