使用Swift 4的KeyPath引用自身

4

在Swift 4的新的KeyPath中,有没有办法引用self

像这样可以正常工作,我们可以访问对象的属性:

func report(array: [Any], keyPath: AnyKeyPath) {
    print(array.map({ $0[keyPath: keyPath] }))
}

struct Wrapper {
    let name: String
}

let wrappers = [Wrapper(name: "one"), Wrapper(name: "two")]
report(array: wrappers, keyPath: \Wrapper.name)

但是,我觉得直接处理一个对象本身是不可能的:

let strings = ["string-one", "string-two"]
report(array: strings, keyPath: \String.self) // would not compile

我觉得应该有一种明显的方法可以做到这一点?
编辑:
或者简单地说:
let s = "text-value"
print(s[keyPath: \String.description]) // works fine
print(s[keyPath: \String.self]) // does not compile

@Sulthan 在处理任意对象数组的情况下,通过指定一个提供标题的属性的键路径,这种方法是非常合理的。通过像在Objective-C中一样指定到self的键路径,我们可以使用所提供对象的实例作为它们的标题。 - bteapot
我认为编程语言应该支持“自身键路径”(使用您尝试使用的确切语法,例如\String.self),欢迎提交改进建议或在Swift论坛上提出。一段时间以前,我构建了一个强类型的Firebase数据库包装器,它可以使用键路径(因此您可以说诸如someProvider.observeValue(at: \.someProperty) { ... }之类的内容),而自身键路径将非常有用(当时我只是通过添加一个计算属性来实现它,该属性仅返回self)。 - Hamish
@Hamish 该死的我,原来是方法的问题!extension String { var instance: String { return self } } 允许使用\String.instance。请写下您的答案,我会接受它。 - bteapot
3个回答

4
很遗憾,Swift keypaths目前不支持这种操作。但是,我认为他们应该支持这种操作(使用您尝试使用的确切语法,例如\String.self)。所有表达式都有一个隐含的.self成员,它只是评估表达式,因此允许在keypaths中使用.self似乎是一种完全自然的扩展(编辑:现在正在推销这个功能)。在支持之前(如果支持),您可以通过协议扩展进行“hack”,添加一个计算属性,只需转发到self即可。
protocol KeyPathSelfProtocol {}
extension KeyPathSelfProtocol {
  var keyPathSelf: Self {
    get { return self }
    set { self = newValue }
  }
}

extension String : KeyPathSelfProtocol {}

let s = "text-value"
print(s[keyPath: \String.description])
print(s[keyPath: \String.keyPathSelf])

您只需要将希望使用“self keypaths”的类型符合 KeyPathSelfProtocol 协议即可。

3

是的,有一种方法可以引用self,但它在Swift 4中不可用。它于2018年9月为Swift 5实现,并称为Identity key path

您可以像您建议的那样使用它

let s = "text-value"
print(s[keyPath: \String.self]) // works in Swift 5.0

尽管Swift 5尚未发布,但您可以通过下载开发版本https://swift.org/download/#releases来尝试它。


0

keyPath 的行为类似于键值编码:通过 key 订阅获取类 / 结构体的 成员 值。

在 Swift 中,self 不是类的成员,而是 description

你会期望得到什么结果?

report(array: wrappers, keyPath: \Wrapper.self)

实际上,您可以在Objective-C对象上执行obj.value(forKey: "self"),因此行为并不完全相同。 - Martin R
@MartinR 好的,我稍微改了一下措辞。 - vadian
@vadian 是的,我知道 self 不是 Swift 类或结构体的属性。我正在寻找一种方法来接收我应用键路径的相同对象实例。 - bteapot
很抱歉,您不能使用 keyPath - vadian
很遗憾,那是Objective-C中一种优雅的模式。所以...看来我必须采用对象包装器。 :) - bteapot
所有表达式都有一个隐含的 self 成员(它只是求值为该表达式),例如,您可以说 let s = "foo"; print(s.self)。在键路径中允许使用 .self 看起来像是一种非常自然的扩展。 - Hamish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接