map (keyPath) 여기서 keyPath는 변수입니다.

Sep 06 2020
let arr = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
arr.map(\.0) // [1, 2, 3, 4, 5]

잘 작동합니다. 그러나 아래 코드는 컴파일되지 않습니다.

let keyPath = \(Int, Int).0
arr.map(keyPath)

'WritableKeyPath <(Int, Int), Int>'유형의 값을 예상 인수 유형 '((Int, Int)) throws-> T'로 변환 할 수 없습니다.
일반 매개 변수 'T'를 유추 할 수 없습니다.

답변

4 NewDev Sep 06 2020 at 20:41

Array.map서명이있는 클로저를 기대합니다 (Element) throws -> T.

Swift 5.2에서 키 경로는 함수 / 폐쇄 ( 진화 제안이 있습니다 ) 로 전달 될 수 있었지만 리터럴로만 전달되었습니다 (적어도 제안에 따르면 "현재"라고 표시되어 있으므로이 제한은 해제 될 것입니다.) ).

이를 극복하기 위해 Sequence키 경로를 허용 하는 확장을 만들 수 있습니다 .

extension Sequence {
   func map<T>(_ keyPath: KeyPath<Element, T>) -> [T] {
      return map { $0[keyPath: keyPath] }
   }
}

(크레딧 : https://www.swiftbysundell.com/articles/the-power-of-key-paths-in-swift/)

그런 다음 원하는 작업을 수행 할 수 있습니다.

let keyPath = \(Int, Int).0
arr.map(keyPath)
Jessy Sep 06 2020 at 22:24

진화 제안은 연산자를 사용하여 수행하는 방법을 보여 주었지만 첨자 및 함수에는 인수가 필요하지 않기 때문에 부분적으로 적용되었는지 여부에 관계없이 동일한 구문 []이나 ()구문을 사용할 수도 있습니다 .

let oneTo5 = 1...5
let keyPath = \(Int, Int).0
XCTAssert(
  zip(oneTo5, oneTo5).map(keyPath[]).elementsEqual(oneTo5)
)
let keyPath = \Double.isZero
XCTAssertFalse(keyPath[1.0]())
public extension KeyPath {
  /// Convert a `KeyPath` to a partially-applied get accessor.
  subscript() -> (Root) -> Value {
    { $0[keyPath: self] } } /// Convert a `KeyPath` to a get accessor. subscript(root: Root) -> () -> Value { { root[keyPath: self] } } } public extension ReferenceWritableKeyPath { /// Convert a `KeyPath` to a partially-applied get/set accessor pair. subscript() -> (Root) -> Computed<Value> { { self[$0] }
  }

  /// Convert a `KeyPath` to a get/set accessor pair.
  subscript(root: Root) -> Computed<Value> {
    .init(
      get: self[root],
      set: { root[keyPath: self] = $0 }
    )
  }
}


/// A workaround for limitations of Swift's computed properties.
///
/// Limitations of Swift's computed property accessors:
/// 1. They are not mutable.
/// 2. They cannot be referenced as closures.
@propertyWrapper public struct Computed<Value> {
  public typealias Get = () -> Value
  public typealias Set = (Value) -> Void

  public init(
    get: @escaping Get,
    set: @escaping Set
  ) {
    self.get = get
    self.set = set
  }

  public var get: Get
  public var set: Set

  public var wrappedValue: Value {
    get { get() }
    set { set(newValue) }
  }

  public var projectedValue: Self {
    get { self }
    set { self = newValue }
  }
}

//MARK:- public
public extension Computed {
  init(
    wrappedValue: Value,
    get: @escaping Get = {
      fatalError("`get` must be assigned before accessing `wrappedValue`.")
    },
    set: @escaping Set
  ) {
    self.init(get: get, set: set)
    self.wrappedValue = wrappedValue
  }
}