Opaque Types(1)


🌟 불투명(opaque) 반환 타입을 가진 함수나 메소드는 반환 값의 타입 정보 를 숨김
🌟 함수의 반환 타입으로 고정(concrete)타입을 제공하는 대신 반환 값을 자신이 지원하는 프로토콜로 설명
🌟 타입 정보를 감추는 것은 반환 값의 실제 타입을 개인 전용(private)으로 남길 수 있기 때문에 모듈과 그 모듈을 호출하는 코드의 경계선 상에서 유용
🌟 프로토콜 타입인 값을 반환하는 것과는 달리, 불투명 타입타입 정체성(type identity)을 보존
🌟 컴파일러는 타입 정보에 접근할 수 있지만, 모듈 사용자는 접근불가

✅ 불투명 타입이 푸는 문제

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 joinedTriangle = JoinedShape(top: smallTriangle, bottom: flippedTriangle)
print(joinedTriangle.draw())

💻 출력 :

*
**
***
***
**
*

  • 이 접근 방식으로 두 도형을 수직으로 갖다 붙이는 JoinedShape<T: Shape, U: Shape> 구조체를 정의하는 것은 ‘뒤집힌 삼각형’을 다른 삼각형과 갖다 붙임으로써JoinedShape<Triangle, FlippedShape<Triangle>> 같은 타입이 되버림

✅ 불투명 타입 반환하기

func max<T>(_ x: T, _ y: T) -> T where T: Comparable { ... }
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())
func flip<T: Shape>(_ shape: T) -> some Shape {
  return FlippedShaped(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())
func invalidFlip<T: Shape>(_ shape: T) -> some Shape {
  if shape is Square {
    return shape                      // 에러: 반환 타입이 일치하지 않음
  }
  return FlippedShape(shape: shape)   // 에러: 반환 타입이 일치하지 않음
}
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 `repeat`<T: Shape>(shape: T, count: Int) -> some Collection {
  return Array<T>(repeating: shape, count: count)
}

✅ 불투명 타입과 프로토콜 타입의 차이

func protoFlip<T: Shape>(_ shape: T) -> Shape {
  return FlippedShape(shape: shape)
}
func protoFlip<T: Shape>(_ shape: T) -> Shape {
  if shape is Square {
    return shape
  }
  return FlippedShape(shape: shape)
}
let protoFlippedTriangle = protoFlip(smallTriangle)
let sameThing = protoFlip(smallTriangle)
protoFlippedTriangle == sameThing     //  에러
protocol Container {
  associatedtype Item
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}
extension Array: Container { }
// 에러: '결합 타입' 을 가진 프로토콜은 반환 타입으로 사용할 수 없음
func makeProtocolContainer<T>(item: T) -> Container {
  return [item]
}

// 에러: 'C' 를 추론하기 위한 충분한 정보가 없음
func makeProtocolContainer<T, C: Container>(item: T) -> C {
  return [item]
}
func makeOpaqueContainer<T>(item: T) -> some Container {
  return [item]
}

let opaqueContainer = makeOpaqueContainer(item: 12)
let twelve = opaqueContainer[0]
print(type(of: twelve))
// "Int" 를 인쇄합니다.
profile
iOS 개발자😺

0개의 댓글

Powered by GraphCDN, the GraphQL CDN