Swift Opaque Types
Hide implementation details about a valueโs type.
1. Opaque Types ๐ฉโ๐ป
์ฐ๋ฆฌ๋ ์ด๋ฏธ Generics
์์ Opaque Types
๋ฅผ ๋ณธ ์ ์๋ค. ํจ์ ๋๋ ๋ฉ์๋์ return type ์ Type
์ด ์๋ some Type
์ผ๋ก ๋ฐ๊ฟ Type ์ ์ผ๋ถ์์
์์ํ ๋ฟ ๋ช
ํํ Type ์ ๋ณด๋ฅผ ๊ฐ์ถ๋ค.
์ด๋ ๊ฒ ์์ธํ ์ ๋ณด๋ฅผ ๊ฐ์ถ๋ ๊ฒ์ ๋ชจ๋
๊ณผ ๋ชจ๋์ ํธ์ถํ๋ ์ฝ๋
์ฌ์ด์ ๊ฒฝ๊ณ(boundaries)
์์ ์ ์ฉํ๋ค. Protocol Type ์ ๊ฐ์
๋ฐํํ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ Opaque Type ์ Type Identity
๋ฅผ ์ ์งํ๋ค(Compiler ๋ Type ์ ์ ๋ณด์ ์ ๊ทผํ ์ ์์ง๋ง, ๋ชจ๋์
ํด๋ผ์ด์ธํธ๋ ์ ๊ทผํ ์ ์๋ค).
2. The Problem That Opaque Types Solve ๐ฉโ๐ป
1. Triangle
Opaque Types ๊ฐ ํด๊ฒฐ ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ธฐ ์ํด ๊ธฐ์กด์ Nonopaque Types ๋ฒ์ ์ ์ฝ๋๋ฅผ ๋ง๋ค์ด๋ณด์. ๋ค์์ ASCII ๊ทธ๋ฆผ ๋ชจ์์
๊ทธ๋ฆฌ๋ ๋ชจ๋๋ก์จ String ์ ๋ฐํํ๋ draw()
ํจ์๋ฅผ ์๊ตฌ์ฌํญ์ผ๋ก ์ ์ํ๋ Shape
protocol ๊ณผ ์ด๊ฒ์ ์ค์ํ๊ธฐ ์ํ Triangle
structure ๋ค.
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(type(of: smallTriangle)) // Triangle
print(smallTriangle) // Triangle(size: 3)
๊ทธ๋ฆฌ๊ณ ์ด Triangle(size: 3)
์ด draw()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด result ์๋ ["*", "**", "***"]
๊ฐ ๋ด๊ธฐ๊ฒ ๋ ๊ฒ์ด๋ค. draw()
๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ joined(separator:)
๋ฉ์๋์ ์๋์ ๋จผ์ ์ดํด๋ณด์.
var arr = ["*", "**", "***"]
print(arr) // ["*", "**", "***"]
print(arr.joined()) // ******
print(arr.joined(separator: ", ")) // *, **, ***
์ด์ ์ด๋ค ๊ทธ๋ฆผ์ด ๊ทธ๋ ค์ง์ง ์์ํ ์ ์์ ๊ฒ์ด๋ค. ๋ฉ์๋๋ฅผ ํธ์ถํด ๊ทธ๋ฆผ์ ๊ทธ๋ ค๋ณด์.
print(smallTriangle.draw())
*
**
***
*\n**\n***
๊ฐ ์ ์ฅ๋์ด ์์ ๊ฐ์ด ์ถ๋ ฅ๋๋ค.
2. FlippedShape
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
Generic Types ๋ฅผ ์ด์ฉํด FlippedShped
Structure ๋ฅผ ๊ตฌํํ๋ค. ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ์ค์ํ ์ ์ฝ์ด ์๋๋ฐ,
๋ค์งํ ๊ฒฐ๊ณผ(flipped result)๋ฅผ ์์ฑํ๋๋ฐ ์ฌ์ฉ๋ Exact Generic Type ์ ๋
ธ์ถ(expose)
์ํจ๋ค.
let flippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle.draw())
***
**
*
๋ชจ๋ ์ฌ์ฉ์๊ฐ ์์์ผ ํ๋ ๊ฒ์ ๋ชจ๋ ์ฌ์ฉ์๊ฐ ์ ๊ณต๋ฐ๊ธฐ๋ก ํ Shape
protocol ์ ๋ฌด์ธ๊ฐ (์ด ๊ฒฝ์ฐ draw()
๋ฉ์๋)๋ฟ์ด๋ค.
๊ทธ๋ฐ๋ฐ Shape Protocol ์ ์ค์ํ๋๋ก draw()
๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด Structure flippedTriangle ๋ฅผ ๊ทธ๋๋ก ๋
ธ์ถํ๋ฉด ์ฌ๊ธฐ ์ฌ์ฉ๋
Wrapper
์ธ FlippedShape
๊ฐ ๊ทธ๋๋ก ๋
ธ์ถ๋๋ค(= ๋ค์งํ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋๋ฐ ์ฌ์ฉ๋ Exact Generic Type ์ ๋
ธ์ถ์ํจ๋ค).
print(flippedTriangle.shape) // Triangle(size: 3)
Wrapper
์ Exact Generic Type ์ด ๋ ธ์ถ๋์ด ๋ถํ์ํ ์ ๋ณด(FlippedShape ์ โshapeโ Property)๊ฐ ๋ ธ์ถ๋๋ค.
3. JoinedShape
์ด๋ฒ์๋ Shape Protocol ์ ์ค์ํ๋ 2๊ฐ์ shape ์ ๊ฒฐํฉํ๋ Structure ๋ฅผ ์ ์ํด๋ณด์.
struct JoinedShape<T: Shape, U: Shape>: Shape {
var top: T
var bottom: U
func draw() -> String {
top.draw() + "\n" + bottom.draw()
}
}
JoinedShape<T: Shape, U: Shape>
structure ๋ 2๊ฐ์ shapes ๋ฅผ ์์ง์ผ๋ก ๊ฒฐํฉํ๋ค.
์ด๊ฒ์ ์๋ ์ ์ฝ๋์ ๊ฐ์ด Flipped Triangle ์ Another Triangle ๊ณผ ๊ฒฐํฉํด
JoinedShape<FlippedShape<Triangle>, Triangle>
๊ณผ ๊ฐ์ return type ์ ์์ฑํ๋ค.
let joinedTriangles = JoinedShape(top: smallTriangle, bottom: flippedTriangle)
print(joinedTriangles.draw())
*
**
***
***
**
*
shape ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ํด ์์ธํ ์ ๋ณด๋ฅผ ๋
ธ์ถํ๋ฉด, Full Return Type
์ ๋ช
์ํด์ผํ๊ธฐ ๋๋ฌธ์ ASCII ๊ทธ๋ฆผ ๋ชจ์์ ๊ทธ๋ฆฌ๋ ๋ชจ๋์
public interface ์ ํฌํจ๋์ง ์์ Type ์ด ์ ์ถ๋ ์ ์๋ค.
print(joinedTriangles.top) // Triangle(size: 3)
print(joinedTriangles.bottom) // FlippedShape<Triangle>(shape: __lldb_expr_38.Triangle(size: 3))
๋ชจ๋ ๋ด์ ์ฝ๋๋ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ๋ชจ์์ ๋ง๋ค ์ ์์ผ๋ฉฐ, ๋ชจ๋ ์ธ๋ถ์ ๋ค๋ฅธ ์ฝ๋๋ ์ด ๋ชจ๋์ ๊ตฌํ ๋ชฉ๋ก๊ณผ ๊ฐ์ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ํ์๊ฐ ์๋ค.
๋ฐ๋ผ์ FlippedShape, JoinedShape ์ ๊ฐ์
Wrapper Types
๋ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ค์ํ์ง ์์ผ๋ฉฐ,ํ์๋์ง ์์์ผํ๋ค
. ๋ชจ๋์ public interface ๋ shape ์ ๊ฒฐํฉํ๊ฑฐ๋ ๋ค์ง๋ ๊ฒ๊ณผ ๊ฐ์ ์์ ์ผ๋ก ๊ตฌ์ฑ๋๋ฉฐ, ์ด๋ฌํ ์์ ์ ๋ ๋ค๋ฅธShape
๊ฐ์ ๋ฐํํ๋ค.
3. Returning an Opaque Type ๐ฉโ๐ป
1. Square & makeTrapezoid()
Opaque Types ๋ Generic Types ์ ๋ฐ๋๋ก ์๊ฐํ ์ ์๋ค.
Generic Types ๋ฅผ ์ฌ์ฉํ๋ฉด, ํจ์๋ ์ถ์ํ๋ ๋ฐฉ์(abstracted away)์ผ๋ก ๊ฐ์ ๋ฐํํ ์ ์์ผ๋ฉฐ, return type ์ ํจ์๊ฐ ํธ์ถ๋ ๋
๊ฒฐ์
๋๋ค.
func max<T>(_ x: T, _ y: T) -> T where T: Comparable { ... }
max(_:_:)
ํจ์๋ ํธ์ถํ๋ ์ฝ๋์ x, y ๊ฐ์ ๋ฐ๋ผ T
์ Type ์ด ์ ํด์ง๊ณ , ์ด T
๋ Comparable
protocol ์ ์ค์ํ๋ ์ด๋ค
Types ๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
๋ฐ๋ฉด Opaque Types ๋ฅผ ๋ฐํํ๋ ํจ์์ ๊ฒฝ์ฐ ์ด๋ฌํ ์ญํ ์ด ๋ฐ์ ๋๋ค. Opaque Types ๋ฅผ ์ฌ์ฉํ๋ฉด, ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ก๋ถํฐ ์ถ์ํ๋
๋ฐฉ์์ผ๋ก ํจ์์ ๊ตฌํ์์ return type ์ ์ ํ
ํ ์ ์๋ค.
์์์ FlippedShape, JoinedShape ๋ฅผ ๊ทธ๋๋ก ๋
ธ์ถํด ๋ค๋ฅธ ์ ๋ณด๊ฐ ๋
ธ์ถ๋์๋๋ฐ
Shape
protocol ์ด ์ ๊ณตํ๊ธฐ๋ก ์ฝ์ํ draw()
๋ง ๋
ธ์ถ๋๋ฉด ๋๋ฏ๋ก
struct SomeStructure: Shape {
func draw() -> String { something }
}
์ ๊ฐ์ด FlippedShape, JoinedShape ๋ก๋ถํฐ return type ์ ์ ํํด ๋ถํ์ํ ์ ๋ณด๋ฅผ ํฌํจํ์ง ์๋ ๊ฐ๋จํ ํํ๋ก Wrapping ๋ ๊ฐ์ ์ ๊ณตํด์ผํ๋ค.
Opaque Types ๋ฅผ return type ์ผ๋ก ์ ์ํ ๋ ๊ฐ๋ฅํ Types ๋ ๋ค์๊ณผ ๊ฐ๋ค.
An 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class
๋ค์ ์์ ๋ฅผ ์ํด ์ฌ๊ฐํ์ ๊ทธ๋ฆฌ๋ Square
structure ๋ฅผ ์ถ๊ฐ๋ก ์ ์ํ์.
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")
}
}
๋ค์ ์์ ์์ ํจ์ makeTrapezoid()
๋ shape ์ ๋ช
ํํ Type ์์ด ์ฌ๋ค๋ฆฌ๊ผด(trapezoid)์ ๋ฐํํ๋ค.
(์ฌ์ฉ์์๊ฒ Triangle, Square, FlippedShape, JoinedShape ์ Exact Generic Type ์ด ๋
ธ์ถ๋์ง ์๋๋ค.)
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())
*
**
**
**
**
*
๊ทธ๋ ๋ค๋ฉด Nonopaque Types ์์ ์ ์ํ JoinedShape ์ ๋ญ๊ฐ ๋ค๋ฅผ๊น? ํ๋ฒ ๋น๊ตํด๋ณด๋๋ก ํ์.
print(joinedTriangles.top) // Triangle(size: 3)
print(joinedTriangles.bottom) // FlippedShape<Triangle>(shape: __lldb_expr_38.Triangle(size: 3))
๋ชจ๋์ ์ฌ์ฉ์๋ draw()
์ ๊ฒฐ๊ณผ๋ง ์๋ฉด ๋๋ค. ๊ทธ๋ฐ๋ฐ JoinedShape
๋ Shape Protocol ์ ์ค์ํ๋ Structure ์์ฒด๋ฅผ ์ ์ํ๊ธฐ
๋๋ฌธ์ ์ด๋ฅผ ๊ตฌํํ๋๋ฐ ์ฌ์ฉ๋ Exact Generic Type JoinedShape
๊ฐ ๋
ธ์ถ๋์ด ์ด๊ฒ์ด ๊ฐ๋ top
๊ณผ bottom
์ ๋ํ ์ ๋ณด๊น์ง
๋
ธ์ถ์ํจ๋ค. ์์์๋ ์ด๋ฏธ ์ค๋ช
ํ๋ฏ์ด FlippedShape, JoinedShape ์ ๊ฐ์
Wrapper Types
๋ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ค์ํ์ง ์์ผ๋ฉฐ, ํ์๋์ง ์์์ผ
ํ๋๋ฐ Structure ๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๋ถํ์ํ ์ ๋ณด๊ฐ ๋
ธ์ถ๋๋ค.
makeTrapezoid()
์ญ์ ํจ์ ๋ด๋ถ์์๋ JoinedShape
๊ฐ ์์ฑํ Structure ๋ก๋ถํฐ top
๊ณผ bottom
์ ์ ๊ทผ ๊ฐ๋ฅํ์ง๋ง
๋ฐํ๋ ๊ฐ์์๋ ์ ๊ทผํ ์ ์๋ค. makeTrapezoid()
๋ Return Type ์
Opaque Type ์ผ๋ก Wrapping
ํด Shape
protocol ์ ์ค์ํ๋ ๊ฐ์ฒด์ ๋ค๋ฅธ ์ ๋ณด๋ฅผ ๋
ธ์ถ์ํค์ง ์๊ณ ๋ชจ๋์ ์ฌ์ฉ์๊ฐ ์์์ผ ํ๋
draw()
๋ง ๋
ธ์ถ์ํจ๋ค.
2. flip(_:)
& join(_:_:)
with Generics
์์์ makeTrapezoid()
ํจ์๋ shape ์ ๋ช
ํํ Type ์์ด some Shape
๋ฅผ ๋ฐํํ๋ค. ์ฆ, Shape
protocol ์ ์ค์ํ๋
Structures ์ Exact Generic Type ๋์
struct SomeStructure: Shape {
func draw() -> String { something }
}
ํํ๋ก Wrapping
ํด ๋ฐํํ๋ค.
An 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class
๋ฅผ ๋ค์ ํ ๋ฒ ๋
๋ ์ฌ๋ ค๋ณด์.
- Generic Types ๊ฐ ํด๊ฒฐํ๋ ๋ฌธ์ ๋ ๋์ผํ body ๋ฅผ ๊ฐ๋ ์ฌ๋ฌ cases ๋ฅผ Type Inference ๋ฅผ ์ฌ์ฉํด ํ๋์ ์ ์๋ก ์ฌ์ฌ์ฉํจ์ผ๋ก์จ ์ฝ๋์ ์ค๋ณต์ ์ต์ํํ๋ ๋ฐฉํฅ์ผ๋ก ์ฝ๋๋ฅผ ์ ์ฐํ๊ฒ ๋ง๋ค์๋ค.
- Opaque Types ๊ฐ ํด๊ฒฐํ๋ ๋ฌธ์ ๋ Types ์ ๋ถํ์ํ ์ ๋ณด ๋
ธ์ถ์ ๋ฐฉ์ง(hiding)ํ๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ํด ํน์
Type
์ ๋ฐํํ๋๋ผ๋ ์์ ๊ฐ์ด ๊ทธType Object
๋ด์์ ๋ฐํ ํ๋ ค๋ ๋จ์ผType Member
๋ง ๋ฐํํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํด์ผํ๋ค. ์ด๊ฒ์ ์ถ์์ ์ธ ํฉ์์ ๊ฒฐ๊ณผ๋ผ ๋ณผ ์ ์์ผ๋ฉฐ, ์ด ๋ชจ๋์ ๊ฐ๋ฐํ๋ ๊ฐ๋ฐ์์ Compiler ๋งType Object
๋ฅผ ์ ์ ์๋ค. ์ด ๋ชจ๋์ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๋ ๋จ์ง ๋งค๋ฒ ๋์ผํType Member
๋ฅผ ์ป๋๋ค๋ ๊ฒ๋ง ์๊ณ ์์ผ๋ฉด ๋๊ณ , ๋งค๋ฒ ๋์ผํ Identity ๋ฅผ ๋ฐํํ๋ ํด๋ผ์ด์ธํธ๋ ์ด return type ์ ๋์ฑ ์ ๋ขฐํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
Return Type ์ผ๋ก
Opaque Types
๋ฅผ ์ฌ์ฉํ๋ ํจ์๊ฐ ์ฌ๋ฌ ์์น์์ ๋ฐํ๋๋ ๊ฒฝ์ฐ, ๊ฐ๋ฅํ ๊ฒฝ์ฐ์ ๋ชจ๋ Return Values ์ Type ์ ๋์ผํด์ผํ๋ค(all of the possible return values must have the same type).์ด๊ฒ์ Generic Functions ์ ๊ฒฝ์ฐ Return Type ์ Generic Types ๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ Return Type
some Type
์ ์ฌ์ ํ Single Type ์ด์ด์ผ ํจ์ ์๋ฏธํ๋ค.
Opaque Types some Shape
๋ฅผ return type ์ผ๋ก ๊ฐ๋ flip(_:)
, join(_:)
ํจ์๋ฅผ ์ถ๊ฐ๋ก ๊ตฌํํด๋ณด์. ์ด๋ฒ์๋
Generics
๋ฅผ ๊ฒฐํฉํด๋ Opaque Types ๊ฐ ์ ์์ ์ผ๋ก ์๋ํ๋์ง ํ์ธํด๋ณธ๋ค.
func flip<T: Shape>(_ shape: T) -> some Shape {
FlippedShape(shape: shape)
}
func join<T: Shape, U: Shape>(_ top: T, _ bottom: U) -> some Shape {
JoinedShape(top: top, bottom: bottom)
}
let smallTriangle = Triangle(size: 3)
let opaqueJoinedTriangles = join(smallTriangle, flip(smallTriangle))
print(opaqueJoinedTriangles.draw())
*
**
***
***
**
*
flip(_:)
๊ณผjoin(_:)
์ ์ํด ๋ฐํ๋opaqueJoinedTriangles
์ญ์draw()
์ธ์๋ ์ ๊ทผํ ์ ์๋ค.
3. invalidFlip(_:)
์์์ Opaque Type ์ return type ์ Single Type
์ด์ด์ผ ํ๋ค๊ณ ํ๋ค. ๋ฐ๋ผ์ ์ด๋ฒ์๋ ์ด ์๊ตฌ์ฌํญ์ ์๋ฐํ๋ ์๋ชป๋ case ๋ฅผ ์ดํด๋ณธ๋ค.
์ flip(_:)
ํจ์๋ฅผ ๋ณด๋ฉด ๊ตณ์ด ์ ์ฌ๊ฐํ์ ์ ์ํ๋ Square
๋ ๋ค์ง์ง ์์๋ ๋ ๊ฒ ๊ฐ๋ค. ๊ทธ๋์ flip(_:)
ํจ์ ์์์ ์ ๋ฌ๋
Shape ์ Type ์ด Square ์ผ ๊ฒฝ์ฐ ๊ทธ๋ฅ ๋ฐํํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ง ๋ค์ง๋ ๊ฒ์ผ๋ก ๋ณ๊ฒฝํ๋ฉด ๋ ์ข์๊ฑฐ๋ผ ํ๋จ๋์ด ์ฝ๋๋ฅผ ์์ ํ๋ค๊ณ
๊ฐ์ ํด๋ณด์.
Opaque Type ์ ๋ฐํํ๊ฒ ๋ค ํด๋๊ณ
Single Type
์ด ์๋ 2๊ฐ์ง Types ๋ก return ์ ํ๋ ค๊ณ ํ์ Compiler ๊ฐ Opaque Type ์ ์๊ตฌ์ฌํญ์ ์๋ฐ๋จ์ ์ธ์งํ๊ณ ์๋ฌ๋ฅผ ์ถ๋ ฅํ๋ค.
- Function declares an opaque return type โsome Shapeโ, but the return statements in its body do not have matching underlying types
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ ์ค ํ๋๋
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")
}
}
Square: Shape
๋ผ๋ ํน์ํ ๊ฒฝ์ฐ๋ฅผ
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
FlippedShape: Shape
์ ๋ด๋ถ๋ก ์ฎ๊ฒจ invalidFlip(_:)
ํจ์๊ฐ ์ธ์ ๋
FlippedShape ์ some Shape ๋ฅผ return
ํ๋๋ก ํ๋ ๊ฒ์ด๋ค.
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")
}
}
๋ณ๊ฒฝ๋ ์ฝ๋๋ฅผ ๋ชจ์ ๋น๊ตํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
flip(_:)
&join(_:_:)
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
func flip<T: Shape>(_ shape: T) -> some Shape {
FlippedShape(shape: shape)
}
let smallTriangle = Triangle(size: 2)
let smallSquare = Square(size: 2)
let trapezoid = join(smallTriangle, join(smallSquare, flip(smallTriangle)))
print(type(of: trapezoid)) // JoinedShape<Triangle, JoinedShape<Square, FlippedShape<Triangle>>>
print(trapezoid.draw())
*
**
**
**
**
*
fixedInvalidFlip(_:)
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")
}
}
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
}
// ๋ฐ๋ผ์ ์ `invalidFlip(_:)`์ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๋ ์ ์๋ค.
func fixedInvalidFlip<T: Shape>(_ shape: T) -> some Shape {
return FlippedShape(shape: shape) // Error: return types don't match
}
let smallTriangle = Triangle(size: 2)
let smallSquare = Square(size: 2)
let trapezoid = join(smallTriangle, join(smallSquare, fixedInvalidFlip(smallTriangle)))
print(type(of: trapezoid)) // JoinedShape<Triangle, JoinedShape<Square, FlippedShape<Triangle>>>
print(trapezoid.draw())
*
**
**
**
**
*
4. repeat(shape:count:)
- Opaque Return Types with Generics
ํญ์ Single Type
์ ๋ฐํํด์ผ ํ๋ค๊ณ ํด์ Opaque Types
๋ฅผ return ํ๋ ํจ์์ Generic Types ์ ์ฌ์ฉ์ ๋ง์ง๋ ์๋๋ค.
๋ค์์ Generic Types ๋ฅผ ์ฌ์ฉํ๋ฉด์ Opaque Types
์ ์๊ตฌ์ฌํญ์ ๋ง์กฑํ๋ ๊ฒฝ์ฐ๋ฅผ ๋ณด์.
์์์ invalidFlip(_:)
ํจ์๊ฐ ๋ถ๊ฐ๋ฅํ๋ ์ด์ ๋
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
}
๋ T
๋ฅผ ๋ฐ์ Square
๋๋ FlippedShape
๋ผ๋ 2๊ฐ์ง Types ๋ก ๋ฐํํ๋ ค ํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ฉด
func `repeat`<T: Shape>(_ shape: T, count: Int) -> some Collection {
Array<T>(repeating: shape, count: count)
}
repeat(shape:count:)
ํจ์ ์ญ์ T
์ ์์กดํ๋ฏ๋ก ๋ฐ๋ T
์ ๋ฐ๋ผ ๋ฐํ๋๋ T
์ Type ์ ๋ณ๊ฒฝ๋์ง๋ง,
some Collection
์ ์ผ๋ถ๋ก์จ Array<T>
๋ผ๋ Single Type ์ผ๋ก Wrapping ๋ Type ์ ๋ฐํ
ํ๊ธฐ ๋๋ฌธ์ Opaque Type ์
์๊ตฌ์ฌํญ์ ์ค์ํ๋ค.
์ด๋ flip(_:) & join(_:_:) ํจ์
func flip<T: Shape>(_ shape: T) -> some Shape {
FlippedShape(shape: shape)
}
func join<T: Shape, U: Shape>(_ top: T, _ bottom: U) -> some Shape {
JoinedShape(top: top, bottom: bottom)
}
์ some Shape
๊ฐ ๊ฐ๊ฐ
struct SomeStructure: Shape {
func draw() -> String { something }
}
๋ผ๋ Single Type ์ผ๋ก Wrapping
๋๋ ๊ฒ๊ณผ ๊ฐ๋ค๊ณ ๋ณผ ์ ์๋ค.
์ ์๋ํ๋์ง ํ์ธํด๋ณด์.
let doubleTriangle = `repeat`(smallTriangle, count: 2)
doubleTriangle.forEach { shape in
if let shape = shape as? Shape {
print(shape.draw())
}
}
*
**
***
*
**
***
let tripleSquare = `repeat`(smallSquare, count: 3)
tripleSquare.forEach { shape in
if let shape = shape as? Shape {
print(shape.draw())
}
}
***
***
***
***
***
***
***
***
***
Opaque Return Types ๋ฅผ Generic ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด
flip(_:)
&join(_:_:)
์ฒ๋ผ Return Type ์Single Type
์ผ๋ก ๋ง๋ค๊ธฐ ์ํด ํ๋์ Type ์ด ๋ค๋ฅธ Types ๋ฅผ ํฌํจํ๋๋ก ๋ง๋ค ํ์ ์์ดsome Type
์Generic
์ ์ฌ์ฉํด ๋ฐํํ๋ฏ๋ก ๊ฐ๊ฐ์ ์ฝ๋๋ฅผ ๋ช ํํ ๋ถ๋ฆฌ์ํฌ ์ ์๋ค.
4. Differences Between Opaque Types and Protocol Types ๐ฉโ๐ป
1. Opaque Types Preserve Type Identity
ํจ์์ return type ์ด Opaque Types ์ธ ๊ฒฝ์ฐ์ Protocol Types ์ธ ๊ฒฝ์ฐ๋ ์ ์ฌํด ๋ณด์ด์ง๋ง ๋ช ํํ ์ฐจ์ด์ ๊ณผ ์๋ก๊ฐ ํด๊ฒฐํ๋ ๋ฌธ์ (์ฌ์ฉํจ์ผ๋ก์จ ์ป๋ ๊ฐ์ )์ด ๋ช ํํ ๋ค๋ฅด๋ค. ์ด๋ฅผ ์ ๋ฆฌํด๋ณด์.
- Opaque Types : ๋ชจ๋์ ํด๋ผ์ด์ธํธ๊ฐ Types ์ ์ ๋ณด์ ์ ๊ทผํ ์ ์๋ค(hiding). Single Type Identity ๋ฅผ ์ ์งํ๋ค. Opaque Type ์ ํ๋์ ํน์ Type ์ ์ฐธ์กฐํ์ง๋ง, ํจ์ ํธ์ถ์๋ ์ด๋ค Type ์ธ์ง ์ ์ ์๋ค.
- Protocol Types : ๋ชจ๋์ ํด๋ผ์ด์ธํธ๊ฐ Types ์ ์ ๋ณด์ ์ ๊ทผํ ์ ์๋ค. Protocols ์ ์ค์ํ๋ ๋ชจ๋ Types ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก Type Identity ๊ฐ ์ ๋์ ์ด๋ค.
2. Strength of Opaque Types and Protocol Types
๋ฐ๋ผ์ ๊ฐ Types ๊ฐ ๊ฐ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
- Opaque Types
some Type
์ ๋ฐํํ๋๋ก ํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด Wrapping ๋์ด ๋ฐํ๋๋ ๋ชจ์์ ๋ณด์.
struct SomeStructure: Shape {
func draw() -> String { something }
}
Types ์ ์ ๋ณด๋ฅผ ์๋ํ(hiding)ํ ์ ์์ ๋ฟ ์๋๋ผ ํน์ Protocols ๋ฅผ ์ค์ํ๋ ๊ฒฝ์ฐ ํด๋น ๋ชจ๋์ด ์ด๋ค Hierarchy ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ณ
์๋ , ์ค๊ฐ์ ๋ชจ๋ ๋ด๋ถ๊ฐ ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋๋ ์ธ์ ๋ one specific type
์ ๋ฐํํ๋ฏ๋ก ํจ์ ํธ์ถ์ ์
์ฅ์์ ๋ณด๋ฉด ์ด๊ฒ์
return type ์ ๋ํ ๊ฐ๋ ฅํ ๋ณด์ฆ์ ์ฝ์(Opaque Type ์ผ๋ก ๋ฐํํ๊ธฐ ์ํด ๋จ์ผ
Identity ๋ฅผ ์ ์งํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํด์ผํ๋ฏ๋ก)ํ๋ ๊ฒ์ด๋ค.
- Protocol Types
ํน์ Protocols ๋ฅผ ์ค์ํ๋ฉด ์ด๋ค Types ๋ ๋ชจ๋ ํ์ฉ๋จ
์ ์๋ฏธํ๋ค. ๊ฒ๋ค๊ฐ Types ์ ์ ๋ณด์ ์ ๊ทผ
๊ฐ๋ฅํ๋ฏ๋ก ํจ์ ํธ์ถ์
์
์ฅ์์ ๋ณด๋ฉด ์ด๊ฒ์ ๋์ ์ ์ฐ์ฑ์ ์ ๊ณตํ๊ณ Original Types ์ ์ ๊ทผ์ด ๊ฐ๋ฅํ๊ฒ ํ๋ค.
3. Protocol Return Type give more Flexibility - protocolFlip(_:)
์์์ ์ธ๊ธํ Protocol Types ์ ๊ฐ์ ์ธ ์ฝ๋๋ฅผ ์ ์ฐํ๊ฒ ๋ง๋๋ ๊ฒ์ ๋ํด ๊ฒ์ฆํด๋ณธ๋ค. ์ฐ๋ฆฌ๋ ์์์ invalidFlip ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Square ์ ํน์ํ ๊ฒฝ์ฐ๋ฅผ FlippedShape ์ ๋ด๋ถ๋ก ์ฎ๊ฒผ๋ค.
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
}
์ด๋ฒ์๋ Square ๋ FlippedShape ์ ์์ ์์ด return type ์ Protocol Types
๋ก ๋ณ๊ฒฝํด๋ณด์.
func protocolFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
let smallTriangle = Triangle(size: 2)
let smallSquare = Square(size: 2)
let trapezoid = join(smallTriangle, join(smallSquare, protocolFlip(smallTriangle)))
print(type(of: trapezoid)) // JoinedShape<Triangle, JoinedShape<Square, FlippedShape<Triangle>>>
print(trapezoid.draw())
*
**
**
**
**
*
Protocol Return Type ์ ๋์ ์ ์ฐ์ฑ์ ์ ๊ณตํด
protocolFlip(_:)
ํจ์๊ฐShape
์FlippedShape
๋ผ๋ ๋ค๋ฅธ Types ๋ฅผ return ํ๋๋ผ๋Shape
protocols ์ ์ค์ํ๋ค๋ฉด ์ด๋ฅผ ํ์ฉํ๋ค.
4. Protocol Return Type cannot use Operations that depend on Type Information
ํ์ง๋ง Protocol Return Type
์ ์ฌ์ฉํ ๋ ์ ์ํด์ผํ ์ ์ด ์๋ค. ์ฝ๋๋ฅผ ์ ์ฐํ๊ฒ ํด์ค์ผ๋ก์จ ๋ง์ ์ฅ์ ์ ๊ฐ๋ ๊ฒ์ ๋ง์ง๋ง
๋ฐ๋๋ก ๋งํ๋ฉด, ์ protocolFlip(_:)
์ return type ์ 2๊ฐ์ ์์ ํ ๋ค๋ฅธ Types
๋ฅผ ๊ฐ๋๋ค.
๋ฐ๋ผ์ Type ์ ๋ณด์ ์์กดํ๋ ๋ง์ ์์ ์ด ๋ฐํ๋ ๊ฐ์์ ์ฌ์ฉํ ์ ์์์ ์๋ฏธํ๋ค.
Triangle ๊ณผ FlippedShape ์ Equatable
์ ์ถ๊ฐํด๋ณด์.
extension Triangle: Equatable {}
extension FlippedShape: Equatable where T == Triangle {
static func == (lhs: FlippedShape<T>, rhs: FlippedShape<T>) -> Bool {
lhs.shape == rhs.shape
}
}
์ด์ Triangle ๊ณผ FlippedShape ์ ==
operator ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
1 ) Returning Opaque Types
let smallTriangle = Triangle(size: 3)
let anotherSmallTriangle = Triangle(size: 3)
print(smallTriangle == anotherSmallTriangle) // true
let flippedTriangle = FlippedShape(shape: smallTriangle)
let anotherFlippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle == anotherFlippedTriangle) // true
2 ) Returning Protocol Types
let protocolFlippedTriangleA = protocolFlip(smallTriangle)
let protocolFlippedTriangleB = protocolFlip(smallTriangle)
print(type(of: flippedTriangle)) // FlippedShape<Triangle>
print(type(of: protocolFlippedTriangleA)) // FlippedShape<Triangle>
์ฐ์ Initializer ์ ์ํด ์์ฑ๋ flippedTriangle
๊ณผ Protocol Return Type์ ์ํด ๋ฐํ๋
protocolFlippedTriangleA
์ ๋ ๋ค ๋์ผํ FlippedShape<Triangle>
Type ์์ด ํ์ธ๋๋ค.
print(protocolFlippedTriangleA == protocolFlippedTriangleB) // error: Binary operator '==' cannot be applied to two 'any Shape' operands
ํ์ง๋ง Protocol Return Type
์ ==
operator ๋ฅผ ์ฌ์ฉํ ์ ์์ด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
5. Downcasting Protocol Return Types
๋ง์ฝ ์ ๊ฒฝ์ฐ Protocols ๋ฅผ ์ด์ฉํ ์ ์ฐ์ฑ์ ์ฅ์ ์ ํ์ฉํ๋ฉด์, Types ์ ์ ๋ณด๋ฅผ ํ์ฉํ๊ณ ์ ํ๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์ ์ ๋ค๋ฅธ ์ธ์ด์ ์ด์ผ๊ธฐ๋ฅผ ์ดํด๋ณด์. ๋ง์ฝ Java ์ ๊ฐ์ ์ธ์ด๋ฅผ ํด๋ดค๋ค๋ฉด ์ด๋ค ํจ์์ return ๊ฐ์ ๋ฐ์ ๋ณ์์ ํ ๋นํ ๋
ArrayList<String>
, LinkedList<String>
์ ๊ฐ์ด ๋ช
ํํ Types ๋ฅผ ์ ์ธํด ๋ฐ์ง ์๊ณ , Interface ๋ฅผ ์ด์ฉํด
List<String>
์ผ๋ก ๋ฐ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ค.
List<String> result = someFunction() // return `ArrayList<String>` or `LinkedList<String>` or anything adopt to 'List' interface.
์ด๋ ์ด ํฌ์คํ
์ ์์ํ ๋ ์ค๋ช
ํ๋ ์์ธํ ์ ๋ณด๋ฅผ ๊ฐ์ถ๋ ๊ฒ์ '๋ชจ๋'๊ณผ '๋ชจ๋์ ํธ์ถํ๋ ์ฝ๋' ์ฌ์ด์ '๊ฒฝ๊ณ(boundaries)'์์ ์ ์ฉํ๋ค
๋
์ค๋ช
๊ณผ ์ ์ฌํจ์ ๋ณด์ฌ์ค๋ค.
์ด๋ ๊ฒ boundaries ์์ ์ ์ฐ์ฑ์ ํ๋ณดํ๋ ๋์ result
๋ List ๊ฐ ๊ณตํต์ผ๋ก ๊ฐ์ง๊ณ ์๋ ๋ฉ์๋๋ ์ฌ์ฉํ ์ ์์ผ๋,
ArrayList ๋ LinkedList etc...
๋ง ๊ฐ์ง๊ณ ์๋ ์ ์ฉ ๋ฉ์๋๋ ์ฌ์ฉํ ์ ์๋ค. ๋ง์ฝ, ์ ์ฉ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Downcasting
์
ํด์ผํ๋ค.
๋ค์ Swift ๋ก ๋์์๋ณด์. flippedTriangle
์ protocolFlippedTriangleA
์ ๋์ผํ Type ์ด์ง๋ง
Protocol Return Type์ ์ํด ๋ฐํ๋ protocolFlippedTriangleA ๋ง ==
operator ๋ฅผ ์ฌ์ฉํ ์ ์์๋ค.
ํ ๋ฒ ์ด๊ฒ์ Downcasting ํด๋ณด์.
let downcastedFlippedTriangleA = protocolFlippedTriangleA as? FlippedShape<Triangle>
let downcastedFlippedTriangleB = protocolFlippedTriangleB as? FlippedShape<Triangle>
print(downcastedFlippedTriangleA == downcastedFlippedTriangleB) // true
์๋๋๋คโผ๏ธ
6. Protocol Has an Associated Type Cannot Use as the Return Types
๋ค์์ Generics ์์ Array ์ ์ฌ์ฉ์๊ฐ ์์ฑํ Container ๋ผ๋ Custom Protocol ์ ๋ํ ์ ํฉ์ฑ์ ์ค์ํ๋๋ก ํ ์ฝ๋์ ์ผ๋ถ๋ค.
protocol IntContainer {
mutating func append(_ item: Int)
var count: Int { get }
subscript(i: Int) -> Int { get }
}
protocol StringContainer {
mutating func append(_ item: String)
var count: Int { get }
subscript(i: Int) -> String { get }
}
์ฐ๋ฆฌ๋ ์์ ๊ฐ์ ์ฌ๋ฌ Types ์ ๋ํ ๋ฒ์ ์ Container ๋ฅผ ํ๋์ ์ ์๋ก ์ฌ์ฌ์ฉํ๊ณ ์ Associated Types ๋ฅผ ์ฌ์ฉํด ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ์๋ค.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
๊ทธ๋ฆฌ๊ณ Array ๋ ์ด๋ฏธ ์์ ๊ฐ์ ์๊ตฌ์ฌํญ์ ์ค์ํ๊ธฐ ์ํ ๊ตฌํ์ด ์ด๋ฏธ ์กด์ฌํ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ ํฉ์ฑ์ ์ถ๊ฐํ ์ ์์๋ค.
extension Array: Container { }
์ฐ์ Protocols ๊ฐ Protocol Return Type ์ผ๋ก ์ฌ์ฉ๋ ๋์ ๊ฒฝ์ฐ๋ฅผ ์ดํด๋ณด๊ธฐ ์ํด Container Protocol ์ ์๊ตฌ์ฌํญ์ ๋ชจ๋ ์ ๊ฑฐํด๋ณด์.
protocol Container { }
extension Array: Container { }
func makeProtocolContainer<T, C: Container>(item: T) -> C {
[item] // error: Cannot convert return expression of type '[T]' to return type 'C'
}
item ์ด๋ผ๋ ๋ฌด์ธ๊ฐ๋ฅผ ๋ฐ์ Array()
์ ์ ์ฅํด ๋ฐํํ๋ ํจ์๋ค. ์ฐ๋ฆฌ๋ ์์์ Array ๊ฐ Container Protocol ์ ์ค์ํ๋๋ก
ํ์ผ๋ฏ๋ก ์ด๋ฅผ Generic Types ๋ก ์ ์ํด ๋ฐํํ๊ณ ์ ํ๋ค. ์ค์ ๋ก Container Protocol ์ ์๋ฌด๋ฐ ์๊ตฌ์ฌํญ์ด ์์์๋ ๋ถ๊ตฌํ๊ณ
Swift compiler ๋ Generic Type T ๋ฅผ Container Protocol ์ ์ค์ํ๋ Generic Type C ๋ก ๋ณํํ ์ ์๋ค๊ณ ์ด์ผ๊ธฐํ๋ค.
T
๋ Type Inference ๋ฅผ ์ฌ์ฉํ๋๋ฐ, C
๋ Type Inference ๊ฐ ํ์ํ ์ํฉ์ด๋ค. Swift ๋ ์ฌ์ ์ T ์ ๋ํ ์ถฉ๋ถํ
์ ๋ณด๋, C ์ ๋ํ ์ถฉ๋ถํ ์ ๋ณด๋, ๊ฒ๋ค๊ฐ T ์ C ์ ๊ด๊ณ๊ฐ ๊ฐ๋ฅํ์ง์ ๋ํ ์ถฉ๋ถํ ์ ๋ณด๋ ์๋ ์ํฉ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ถํ์ค์ฑ์ ์ค์ด๊ธฐ ์ํด ํจ์๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํด๋ณด์.
func makeProtocolContainer<T>(item: T) -> Container {
[item]
}
Array ๋ Associated Types ๋ฅผ ์ฌ์ฉํด ๋ฌด์์ด๋ ์ ์ฅํ ์ ์๊ณ , Array ๋ Container Protocol ์ ์ค์ํ๋ฏ๋ก ์ด์
makeProtocolContainer(item:)
์ ์๋์ด ๊ฐ๋ฅํ๋ค.
let emptyContainer = makeProtocolContainer(item: 10)
print(type(of: emptyContainer)) // Array<Int>
print(emptyContainer) // [10]
๋ฐ๋ฉด, Array
print(emptyContainer[0]) // error: value of type 'any Container' has no subscripts
Container ๋ Subscript ๋ฅผ ์๊ตฌ์ฌํญ์ผ๋ก ๊ฐ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ ๋ค๋ฉด Container ์ Subscript ์ ๋ํ ์๊ตฌ์ฌํญ์ ์ถ๊ฐํด๋ณด์.
protocol Container {
associatedtype Item
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
Array ๋ ๋ชจ๋ Types ๋ฅผ ์ ์ฅํ ์ ์์ผ๋ฏ๋ก, Container ์ญ์ Array ๊ฐ ์ ์ฅํ ๋ชจ๋ Types ์ ๋ํด Subscript ๊ฐ ์๋ํ๋๋ก ํ๊ธฐ ์ํด Associated Type ์ ์ด์ฉํด ์์ ๊ฐ์ด ์ ํฉ์ฑ์ ์ค์ํ๋๋ก ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
func makeProtocolContainer<T>(item: T) -> Container { // error: Use of protocol 'Container' as a type must be written 'any Container'
[item]
}
๊ทธ๋ฆฌ๊ณ Swift compiler ๋ Replace 'Container' with 'any Container'
๋ผ๋ฉฐ ๊ฒฝ๊ณ ๋ฅผ ๋์ด๋ค.
Associated Types ๋ฅผ ๊ฐ๊ณ ์๋ Protocols ๋ Return Types ๋ก ์ฌ์ฉ๋ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ ์์์ ๋ง๋ฅ๋จ๋ฆฐ
func makeProtocolContainer<T, C: Container>(item: T) -> C {
[item] // error: Cannot convert return expression of type '[T]' to return type 'C'
}
์ ์ ์ฌํ ์ผ์ด์ค๋ผ ํ ์ ์๋ค.
7. Opaque Type Resolve The Problem That Protocol Has an Associated Types
Container Protocol ์ ๋ค์ ์ฒ์ ์ ์ํ๋ ค๋๋๋ก ๋ฐ๊พธ๊ณ Swift compiler ๊ฐ ์ํค๋๋๋ก ๋ฐ๋ผ๊ฐ๋ณด์.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
func makeProtocolContainer<T>(item: T) -> any Container {
[item]
}
let anyContainer = makeProtocolContainer(item: 11)
print(type(of: anyContainer)) // Array<Int>
print(anyContainer) // [11]
print(anyContainer.count) // 1
let eleven = anyContainer[0]
print(type(of: eleven)) // Int
print(eleven) // 11
์ ์์ ์ผ๋ก ์๋ํ๋ค. ์ ๊ฒฝ์ฐ๋ Array ๊ฐ ์ค์ ๋ก Any
Types ์ ๋ํด ๋์ํ ์ ์์ง๋ง Any
๋ AnyObject
๋ ๋ช
ํํ ํ์ํ ์ํฉ์ด
์๋๋ฉด ์ฑ์ ์ฝ๋๋ฅผ Type-Safe
ํ์ง ์๊ฒ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ์ง์ํด์ผํ๋ค.
์ด๋ฐ ์ํฉ์ ํด๊ฒฐํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ์ด ๋ฐ๋ก Opaque Return Types
๋ค!
์ด๋ฒ์๋ ๋ค์ makeProtocolContainer(item:)
ํจ์๋ฅผ Opaque Types some Container
๋ฅผ return ํ๋๋ก ๋ฐ๊ฟ๋ณด์.
func makeProtocolContainer<T>(item: T) -> some Container {
[item]
}
let opaqueContainer = makeProtocolContainer(item: 12)
print(type(of: opaqueContainer)) // Array<Int>
print(opaqueContainer) // [12]
print(opaqueContainer.count) // 1
let twelve = opaqueContainer[0]
print(type(of: twelve)) // Int
print(twelve) // 12
Opaque Return Types
๋ฅผ ์ฌ์ฉํ๋ฉด Any ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ
Associated Types ๋ฅผ ๊ฐ๋ Protocol ์ return ํ ๋์ ๋ฌธ์ ๋ฅผ
ํด๊ฒฐํ ์ ์๋ค.
Reference
- โOpaque Types.โ The Swift Programming Language Swift 5.7. accessed Feb. 27, 2023, Swift Docs Chapter 23 - Opaque Types.