map (keyPath), burada keyPath bir değişken
let arr = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
arr.map(\.0) // [1, 2, 3, 4, 5]
Harika çalışıyor. Ancak aşağıdaki kod derlenmez:
let keyPath = \(Int, Int).0
arr.map(keyPath)
'WritableKeyPath <(Int, Int), Int>' türünün değeri beklenen bağımsız değişken türüne dönüştürülemiyor '((Int, Int)) -> T' atar.
Genel parametre 'T' çıkarılamadı.
Yanıtlar
Array.mapimzalı bir kapanış bekliyor (Element) throws -> T.
Swift 5.2'de, temel yolların işlevler / kapanışlar olarak aktarılmasına izin verildi (burada bir evrim önerisi var ), ancak yalnızca değişmez değerler olarak (en azından, teklife göre, "şimdilik" diyor, bu nedenle belki bu kısıtlama kaldırılabilirdi) ).
Bunun üstesinden gelmek için, üzerinde Sequencebir anahtar yolu kabul eden bir uzantı oluşturabilirsiniz :
extension Sequence {
func map<T>(_ keyPath: KeyPath<Element, T>) -> [T] {
return map { $0[keyPath: keyPath] }
}
}
(kredi: https://www.swiftbysundell.com/articles/the-power-of-key-paths-in-swift/)
O zaman istediğini yapabilirsin:
let keyPath = \(Int, Int).0
arr.map(keyPath)
Evrim önerisi bunun bir operatörle nasıl yapılacağını gösterdi, ancak kısmen uygulanıp uygulanmadığına bakılmaksızın aynı []veya ()sözdizimini de kullanabilirsiniz , çünkü alt simgeler ve işlevler bağımsız değişkenlere ihtiyaç duymaz.
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
}
}