假设我有这个结构:
struct MyStruct {
let x: Bool
let y: Bool
}
Run Code Online (Sandbox Code Playgroud)
在Swift 4中,我们现在可以使用myStruct[keyPath: \MyStruct.x]界面访问它的属性.
我需要的是一种访问所有关键路径的方法,例如:
extension MyStruct {
static func getAllKeyPaths() -> [WritableKeyPath<MyStruct, Bool>] {
return [
\MyStruct.x,
\MyStruct.y
]
}
}
Run Code Online (Sandbox Code Playgroud)
但是,显然,没有我必须手动声明数组中的每个属性.
我怎样才能做到这一点?
免责声明:
请注意,以下代码仅用于教育目的,不应在实际应用程序中使用,如果KeyPath以这种方式使用,可能会包含许多错误/奇怪的行为。
回答:
我不知道你的问题今天是否仍然相关,但挑战很有趣:)
这实际上可以使用镜像 API 实现。
KeyPath API 目前不允许我们从字符串初始化新的 KeyPath,但它确实支持字典“解析”。
这里的想法是构建一个字典来描述struct使用镜像 API,然后迭代键来构建 KeyPath 数组。
Swift 4.2 游乐场:
protocol KeyPathListable {
// require empty init as the implementation use the mirroring API, which require
// to be used on an instance. So we need to be able to create a new instance of the
// type.
init()
var _keyPathReadableFormat: [String: Any] { get }
static var allKeyPaths: [KeyPath<Foo, Any?>] { get }
}
extension KeyPathListable {
var _keyPathReadableFormat: [String: Any] {
let mirror = Mirror(reflecting: self)
var description: [String: Any] = [:]
for case let (label?, value) in mirror.children {
description[label] = value
}
return description
}
static var allKeyPaths: [KeyPath<Self, Any?>] {
var keyPaths: [KeyPath<Self, Any?>] = []
let instance = Self()
for (key, _) in instance._keyPathReadableFormat {
keyPaths.append(\Self._keyPathReadableFormat[key])
}
return keyPaths
}
}
struct Foo: KeyPathListable {
var x: Int
var y: Int
}
extension Foo {
// Custom init inside an extension to keep auto generated `init(x:, y:)`
init() {
x = 0
y = 0
}
}
let xKey = Foo.allKeyPaths[0]
let yKey = Foo.allKeyPaths[1]
var foo = Foo(x: 10, y: 20)
let x = foo[keyPath: xKey]!
let y = foo[keyPath: yKey]!
print(x)
print(y)
Run Code Online (Sandbox Code Playgroud)
请注意,打印输出的顺序并不总是相同(可能是因为镜像 API,但对此不太确定)。
在修改了 rraphael 的回答后,我在 Swift 论坛上询问了这个问题。
有可能,这里讨论:
此外,Swift for TensorFlow 团队已经将其内置到 Swift for TensorFlow 中,这可能会成为纯粹的 Swift:
| 归档时间: |
|
| 查看次数: |
2230 次 |
| 最近记录: |