提问人:hopy 提问时间:1/28/2022 最后编辑:hopy 更新时间:2/1/2022 访问量:815
有没有办法使该方法返回可变值?
Is there any way to make the method return a mutable value?
问:
如下代码所示:
struct Person {
var name: String
}
struct Group {
var person: Person
func callAsFunction() -> Person {
// Person is immutable value
person
}
}
var james = Person(name: "James")
var group = Group(person: james)
group().name = "Wong" //ERROR: Cannot assign to property: function call returns immutable value
group() 返回一个不可变的值,该值无法更改!那么有没有办法让 callAsFunction() 方法返回一个可变值呢?
谢谢;)
更新:
我的想法是将组的所有呼叫和访问转移到组中的 Person 对象,就像直接使用 Person 一样。
我无法使用 dynamicMemberLookup,因为我不知道 Person 中会有什么方法或属性。例如,Person 中可能有 100 个方法和属性(而不是演示的只有一个 name 属性),我不可能用 dynamicMemberLookup 编写 100 个下标方法。
我的需求有点像 Ruby 语言中的代理对象。访问一个对象(组)实际上是访问其中的另一个对象(Person),就好像该组不存在一样。
Ruby 代理模式:https://refactoring.guru/design-patterns/proxy/ruby/example
CallAsFunction 是迄今为止最接近的实现,但要求 Person 不能是 Struct,否则无法将其分配给其属性。
也许还不能在 Swift 中实现此功能?
答:
您使用了错误的动态方法。你想要的是.请密切关注。一、准备工作:dynamicMemberLookup
struct Person {
var name: String
}
@dynamicMemberLookup
struct Group {
var person: Person
subscript(dynamicMember kp:WritableKeyPath<Person,String>) -> String {
get { self.person[keyPath:kp] }
set { self.person[keyPath:kp] = newValue }
}
}
现在看看这让你说了什么:
var group = Group(person: Person(name: "James"))
group.name = "Wong"
print(group.person) // Person(name: "Wong")
你明白了吗?即使 Group 没有属性,我们也会设置 Group,结果是我们设置了 Group 的 The 确实有属性。name
name
name
person
name
评论
简单地返回(的副本),这是一个值类型。然后,您不能像那样改变它的属性。它等效于以下内容:callAsFunction
Person
struct Person {
var name: String
}
Person(name: "Foo").name = "Bar"
这将返回相同的错误:
如果是引用类型,则它本来可以工作,但不适用于值类型。即使你采用了你的值类型,并在改变它之前先将其分配给一个变量,你也只会改变你的副本,而不是原来的。Person
如果你想要你想要的行为,你可以按照 matt (+1) 的建议使用 SE-0195 中概述的 a。@dynamicMemberLookup
你说:
我不能使用,因为我不知道 .例如,可能有 100 个方法和属性(而不是演示的只有一个 name 属性),我不可能用 编写 100 个下标方法。
dynamicMemberLookup
Person
Person
dynamicMemberLookup
您不需要“100 个下标方法”。这是背后的激励思想,即属性将动态确定。例如,这里有两个属性,但只有一个 .@dynamicMemberLookup
Person
Group
@dynamicMemberLookup
struct Person {
var name: String
var city: String
}
@dynamicMemberLookup
struct Group {
var person: Person
subscript(dynamicMember keyPath: WritableKeyPath<Person, String>) -> String {
get { person[keyPath: keyPath] }
set { person[keyPath: keyPath] = newValue }
}
}
var group = Group(person: Person(name: "James", city: "New York"))
group.name = "Wong"
group.city = "Los Angeles"
print(group.person) // Person(name: "Wong", city: "Los Angeles")
如果要处理不同的类型,请将其设置为通用:
struct Person {
var name: String
var city: String
var age: Int
}
@dynamicMemberLookup
struct Group {
var person: Person
subscript<T>(dynamicMember keyPath: WritableKeyPath<Person, T>) -> T {
get { person[keyPath: keyPath] }
set { person[keyPath: keyPath] = newValue }
}
}
和
var group = Group(person: Person(name: "James", city: "New York", age: 41))
group.name = "Wong"
group.city = "Los Angeles"
group.age = 42
print(group.person) // Person(name: "Wong", city: "Los Angeles", age: 42)
评论
@dynamicMemberCallable
评论
group().name
group.name = "Wong"
group().name
callAsFunction
Person
group()
callAsFunction
group.name = "Wong"
group.person.name = "Wong"