μλ νμΈμ. μ€λμ Swiftμ 'λΆν¬λͺ νμ (Opaque Types)'μ λν΄ μμλ³΄κ² μ΅λλ€. λΆν¬λͺ νμ μ κ°μ ꡬ체μ μΈ νμ μ 보λ₯Ό μ¨κΈ°λ©΄μλ νμ μμ μ±μ μ μ§νλ λꡬμ λλ€.
π λΆν¬λͺ νμ μ΄ ν΄κ²°νλ λ¬Έμ
λ¨Όμ λΆν¬λͺ νμ μ΄ νμν μ΄μ μ ν΄κ²°νλ λ¬Έμ λ₯Ό μ΄ν΄ν΄λ³΄κ² μ΅λλ€. λ€μκ³Ό κ°μ΄ ASCII λ¬Έμλ‘ λνμ 그리λ κ°λ¨ν μμ λ₯Ό μ΄ν΄λ΄ μλ€:
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())
// μΆλ ₯:
// *
// **
// ***
μ¬κΈ°μ λνμ λ³ννλ κΈ°λ₯μ μΆκ°ν΄λ΄ μλ€:
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())
// μΆλ ₯:
// ***
// **
// *
κ·Έλ¦¬κ³ λ λνμ κ²°ν©νλ κΈ°λ₯λ μΆκ°ν΄λ΄ μλ€:
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())
// μΆλ ₯:
// *
// **
// ***
// ***
// **
// *
μ¬κΈ°μ λ¬Έμ μ :
μ΄λ κ² μ λ€λ¦μ μ¬μ©νλ©΄ λ°ν νμ μ λͺ¨λ ꡬν μΈλΆ μ λ³΄κ° λ ΈμΆλ©λλ€. μλ₯Ό λ€μ΄ joinedTrianglesμ νμ μ JoinedShape<Triangle, FlippedShape<Triangle>>μ λλ€. μ΄λ° 볡μ‘ν νμ μ:
- ꡬν μΈλΆ μ 보λ₯Ό λ ΈμΆμμΌ APIμ μΆμνλ₯Ό κΉ¨λ¨λ¦½λλ€
- λ΄λΆ ꡬνμ΄ λ³κ²½λλ©΄ κ³΅κ° APIκ° λ³κ²½λ μ μμ΅λλ€
- μ½λλ₯Ό μ΄ν΄νκΈ° μ΄λ ΅κ² λ§λλλ€
π λΆν¬λͺ νμ μΌλ‘ ν΄κ²°νκΈ°
λΆν¬λͺ νμ μ μ΄λ° λ¬Έμ λ₯Ό ν΄κ²°ν©λλ€. some Protocol ꡬ문μ μ¬μ©νμ¬ "νΉμ νμ μ λ°ννμ§λ§ κ·Έ νμ μ΄ λ¬΄μμΈμ§λ μλ €μ£Όμ§ μκ² λ€"λΌκ³ λ§ν μ μμ΅λλ€.
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μ λ°νν©λλ€. ν¨μμ ꡬνμ 볡μ‘ν μ€μ²© νμ μ μ¬μ©νμ§λ§, νΈμΆμλ λ¨μ§ κ·Έκ²μ΄ Shape νλ‘ν μ½μ μ€μνλ€λ κ²λ§ μλ©΄ λ©λλ€.
μ λ€λ¦κ³Ό λΆν¬λͺ νμ μ κ²°ν©ν μλ μμ΅λλ€:
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())
// μΆλ ₯:
// *
// **
// ***
// ***
// **
// *
λΆν¬λͺ νμ μ μ¬μ©νλ©΄ ν¨μκ° κ΅¬ν μΈλΆ μ 보λ₯Ό μ¨κΈ°λ©΄μλ Shape νλ‘ν μ½μ μ€μνλ νΉμ νμ μ λ°νν μ μμ΅λλ€.
μ£Όμμ¬ν: λμΌν νμ λ°ν μꡬ
λΆν¬λͺ νμ μ λ°ννλ ν¨μμ μ€μν μ μ½μ¬νμ νμ λμΌν νμ μ λ°νν΄μΌ νλ€λ κ²μ λλ€. μλ μ½λλ μ»΄νμΌλμ§ μμ΅λλ€:
func invalidFlip<T: Shape>(_ shape: T) -> some Shape {
if shape is Square {
return shape // μ€λ₯: λ°ν νμ
μ΄ μΌμΉνμ§ μμ
}
return FlippedShape(shape: shape) // μ€λ₯: λ°ν νμ
μ΄ μΌμΉνμ§ μμ
}
μ΄ ν¨μλ λλ‘λ Squareλ₯Ό, λλ‘λ FlippedShape<T>λ₯Ό λ°ννλ €κ³ μλνκΈ° λλ¬Έμ μλ¬κ° λ°μν©λλ€.
π λ°μ€ν νλ‘ν μ½ νμ (Boxed Protocol Types)
λΆν¬λͺ νμ κ³Ό λΉμ·νμ§λ§ λ€λ₯Έ κ°λ μΈ 'λ°μ€ν νλ‘ν μ½ νμ 'μ μ΄ν΄λ΄ μλ€. Swiftμμλ any Protocol ꡬ문μ μ¬μ©νμ¬ ννν©λλ€.
struct VerticalShapes: Shape {
var shapes: [any Shape]
func draw() -> String {
return shapes.map { $0.draw() }.joined(separator: "\n\n")
}
}
let largeTriangle = Triangle(size: 5)
let largeSquare = Square(size: 5)
let vertical = VerticalShapes(shapes: [largeTriangle, largeSquare])
print(vertical.draw())
μ¬κΈ°μ [any Shape]λ λ°μ€ν νλ‘ν μ½ νμ μ λ°°μ΄μ λλ€. μ΄ λ°°μ΄μ Shape νλ‘ν μ½μ μ€μνλ μλ‘ λ€λ₯Έ νμ μ κ°λ€μ ν¬ν¨ν μ μμ΅λλ€.
λ°μ€ν νλ‘ν μ½ νμ μ μ¬μ©νλ©΄ νμ μ λ³΄κ° λ°νμκΉμ§ μ§μμ§λ―λ‘(type erasure), νμν λ νμ μΊμ€ν μ ν΅ν΄ μλ νμ μΌλ‘ λ€μ μ κ·Όν μ μμ΅λλ€:
if let downcastTriangle = vertical.shapes[0] as? Triangle {
print(downcastTriangle.size) // 5 μΆλ ₯
}
π λΆν¬λͺ νμ κ³Ό λ°μ€ν νλ‘ν μ½ νμ μ μ°¨μ΄μ
μ΄ λ κ°λ μ μ μ¬ν΄ 보μ΄μ§λ§ μ€μν μ°¨μ΄μ μ΄ μμ΅λλ€:
1. νμ μ μ²΄μ± μ μ§
- λΆν¬λͺ νμ (some Protocol): νΉμ νμ μ μ 체μ±μ μ μ§ν©λλ€. μ»΄νμΌλ¬λ μ€μ νμ μ μκ³ μμ§λ§, νΈμΆμμκ²λ μ¨κΉλλ€.
- λ°μ€ν νλ‘ν μ½ νμ (any Protocol): νμ μ 체μ±μ μ§μ°κ³ λ°νμμ λ€μν νμ μ νμ©ν©λλ€.
2. μ μ°μ±κ³Ό μ±λ₯
- λΆν¬λͺ νμ : μ»΄νμΌ μκ°μ μ€μ νμ μ΄ κ²°μ λλ―λ‘ μ΅μ νκ° κ°λ₯νκ³ μ±λ₯μ΄ μ’μ΅λλ€.
- λ°μ€ν νλ‘ν μ½ νμ : λ°νμ μ μ°μ±μ μ 곡νμ§λ§ κ°μ μ°Έμ‘°(λ°μ±)λ‘ μΈν μ±λ₯ λΉμ©μ΄ μμ΅λλ€.
3. νμ μμ
λ€μ μλ λ°ν νμ μ΄ λ°μ€ν νλ‘ν μ½μΈ ν¨μμ λλ€:
func protoFlip<T: Shape>(_ shape: T) -> any Shape {
return FlippedShape(shape: shape)
}
// λ€λ₯Έ 쑰건μ λ°λΌ λ€λ₯Έ νμ
λ°ν κ°λ₯
func protoFlip<T: Shape>(_ shape: T) -> any Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
let protoFlippedTriangle = protoFlip(smallTriangle)
let sameThing = protoFlip(smallTriangle)
// protoFlippedTriangle == sameThing // μ€λ₯: '==' μ°μ° λΆκ°λ₯
λΆν¬λͺ νμ κ³Ό λ¬λ¦¬ λ°μ€ν νλ‘ν μ½ νμ μ νμ μ 보λ₯Ό 보쑴νμ§ μκΈ° λλ¬Έμ == κ°μ μ°μ°μλ₯Ό μ¬μ©ν μ μμ΅λλ€. λν νμ μ λ³΄κ° μ§μμ§κΈ° λλ¬Έμ μ°κ΄ νμ (Associated Types)μ΄ μλ νλ‘ν μ½κ³Ό ν¨κ» μ¬μ©νλ λ° μ μ½μ΄ μμ΅λλ€.
4. μ°κ΄ νμ μ΄ μλ νλ‘ν μ½
λΆν¬λͺ νμ μ μ°κ΄ νμ μ΄ μλ νλ‘ν μ½μ λ°ν νμ μΌλ‘ μ¬μ©ν μ μκ² ν΄μ€λλ€:
protocol Container {
associatedtype Item
var count: Int { get }
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
// μ€λ₯: μ°κ΄ νμ
μ΄ μλ νλ‘ν μ½μ λ°ν νμ
μΌλ‘ μ¬μ©ν μ μμ
func makeProtocolContainer<T>(item: T) -> Container {
return [item]
}
// λΆν¬λͺ
νμ
μΌλ‘ ν΄κ²°
func makeOpaqueContainer<T>(item: T) -> some Container {
return [item]
}
let opaqueContainer = makeOpaqueContainer(item: 12)
let twelve = opaqueContainer[0] // Int νμ
print(type(of: twelve)) // "Int" μΆλ ₯
μ΄ μμ μμ λΆν¬λͺ νμ μ μ°κ΄ νμ μ΄ μλ νλ‘ν μ½μ λ°ν νμ μΌλ‘ μ¬μ©ν μ μκ² ν΄μ£Όλ©°, νμ μΆλ‘ κΉμ§ κ°λ₯νκ² ν©λλ€.
π λΆν¬λͺ νλΌλ―Έν° νμ (Opaque Parameter Types)
ν¨μ νλΌλ―Έν°μμλ some Protocol ꡬ문μ μ¬μ©ν μ μμ΅λλ€:
func drawTwiceSome(_ shape: some Shape) -> String {
let drawn = shape.draw()
return drawn + "\n" + drawn
}
κ·Έλ¬λ μ€μν μ°¨μ΄μ μ΄ μμ΅λλ€. νλΌλ―Έν° νμ μμ someμ μ¬μ©νλ κ²μ μ§μ ν λΆν¬λͺ νμ μ΄ μλλΌ μ λ€λ¦μ κ°νΈ ꡬ문μ λλ€. μ ν¨μλ λ€μκ³Ό λμΌν©λλ€:
func drawTwiceGeneric<SomeShape: Shape>(_ shape: SomeShape) -> String {
let drawn = shape.draw()
return drawn + "\n" + drawn
}
μ¬λ¬ νλΌλ―Έν°μ someμ μ¬μ©νλ©΄ κ°κ°μ λ 립μ μΈ μ λ€λ¦ νμ μΌλ‘ κ°μ£Όλ©λλ€:
func combine(shape s1: some Shape, with s2: some Shape) -> String {
return s1.draw() + "\n" + s2.draw()
}
// μλ‘ λ€λ₯Έ νμ
μΌλ‘ νΈμΆ κ°λ₯
combine(shape: smallTriangle, with: trapezoid)
μ΄ κ°νΈ ꡬ문μ μ λ€λ¦ where μ μ΄λ λμΌ νμ μ μ½(==)μ μ§μνμ§ μμΌλ―λ‘, 볡μ‘ν μ μ½μ΄ νμν κ²½μ°μλ μ ν΅μ μΈ μ λ€λ¦ ꡬ문μ μ¬μ©ν΄μΌ ν©λλ€.
π μ€μ μ¬μ© μμμ κΆμ₯ μ¬ν
λΆν¬λͺ νμ μ¬μ©μ΄ μ’μ κ²½μ°:
- λΌμ΄λΈλ¬λ¦¬/νλ μμν¬ API λμμΈ: ꡬν μΈλΆ μ 보λ μ¨κΈ°λ νμ μμ μ±μ μ μ§νκ³ μΆμ λ
- λμΌν νμ μ 보μ₯ν΄μΌ νλ κ²½μ°: ν¨μκ° νμ λμΌν ꡬ체μ νμ μ λ°νν΄μΌ ν λ
- μ°κ΄ νμ μ΄ μλ νλ‘ν μ½: μ λ€λ¦ μ μ½μΌλ‘ μ¬μ©νκΈ° μ΄λ €μ΄ νλ‘ν μ½μ λ°νν΄μΌ ν λ
- μ»΄νμΌ μκ° μ΅μ νκ° μ€μν κ²½μ°: μ±λ₯μ΄ μ€μνκ³ νμ μ λ³΄κ° νμν λ
λ°μ€ν νλ‘ν μ½ νμ μ¬μ©μ΄ μ’μ κ²½μ°:
- μ΄μ’ 컬λ μ : λ€μν νμ μ κ°μ²΄λ₯Ό νλμ 컬λ μ μ μ μ₯ν΄μΌ ν λ
- λ°νμμ νμ μ΄ κ²°μ λλ κ²½μ°: μ¬μ©μ μ λ ₯μ΄λ λμ λ°μ΄ν°μ λ°λΌ λ€λ₯Έ νμ μ μ¬μ©ν΄μΌ ν λ
- νμ μ 체μ±μ΄ μ€μνμ§ μμ κ²½μ°: λ€μν νμ μ κ°μ²΄λ₯Ό μ²λ¦¬νλ μ½λμμ
π μμ½
λΆν¬λͺ νμ (some Protocol)μ Swiftμ κ°λ ₯ν κΈ°λ₯μΌλ‘, ꡬν μΈλΆ μ 보λ₯Ό μ¨κΈ°λ©΄μλ νμ μμ μ±μ μ μ§ν μ μκ² ν΄μ€λλ€. μ΄λ μ λ€λ¦κ³Ό κ²°ν©νμ¬ APIλ₯Ό λμ± ννλ ₯ μκ³ μ μ°νκ² λ§λ€ μ μμ΅λλ€.
λ°λ©΄ λ°μ€ν νλ‘ν μ½ νμ (any Protocol)μ λ°νμ μ μ°μ±μ μ 곡νμ§λ§ νμ μ 보λ₯Ό μ§μ°λ―λ‘ μΌλΆ νμ κΈ°λ° μμ μ΄ μ νλ©λλ€.
'π₯ Bread Basics > Swift' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
Swift 곡μ λ¬Έμ μ 리 - κ³ κΈ μ°μ°μ (Advanced Operators) (1) | 2025.04.13 |
---|---|
Swift 곡μ λ¬Έμ μ 리 - μ κ·Ό μ μ΄ (Access Control) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - λ©λͺ¨λ¦¬ μμ μ± (Memory Safety) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - μλ μ°Έμ‘° μΉ΄μ΄ν (Automatic Reference Counting) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - μ λλ¦ (Generics) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - νλ‘ν μ½ (Protocols) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - νμ₯ (Extensions) (0) | 2025.04.13 |
Swift 곡μ λ¬Έμ μ 리 - μ€μ²©λ νμ (Nested Types) (1) | 2025.04.12 |