Swift 将与值关联的值类型进行适当的变异
在Swift中,是否可以变异与枚举关联的值(这是一种值类型)?如果是,如何进行Swift 将与值关联的值类型进行适当的变异,swift,enums,pass-by-reference,value-type,Swift,Enums,Pass By Reference,Value Type,在Swift中,是否可以变异与枚举关联的值(这是一种值类型)?如果是,如何进行 struct S { var a = 1 } enum E { case s(S) } var e = E.s(S()) // the goal is to make e hold s with a = 2 // overwriting e is not allowed if case var .s(s) = e { // s is a copy at this point
struct S {
var a = 1
}
enum E {
case s(S)
}
var e = E.s(S())
// the goal is to make e hold s with a = 2
// overwriting e is not allowed
if case var .s(s) = e {
// s is a copy at this point
// I want to mutate e in-place
s.a = 2
}
注意:这似乎是可能的,至少对于可选的枚举s?.a=2
变异可选的
用例:
我正在编写一个关于Codable
的小包装器,以便轻松地在字典和对象之间映射值。我有一个MappingContext
,它是encode
或decode
。假设KeyedEncodingContainer
在编码时有一个变异函数,我希望此包装的用户避免重新分配值,而只是直接变异关联的值
我打开了swift stdlib代码,该函数甚至没有改变结构,但标记为mutating。不知道为什么,但我现在可以没有问题地复制,而且重新分配是一个可以接受的解决方案,只是想确保我没有遗漏任何明显的内容
typealias EncodeContainer = KeyedEncodingContainer<JsonCodingKey>
typealias DecodeContainer = KeyedDecodingContainer<JsonCodingKey>
public enum CodingMode {
case encode(EncodeContainer)
case decode(DecodeContainer)
}
typealias EncodeContainer=KeyedEncodingContainer
typealias DecodeContainer=KeyedDecodeContainer
公共枚举编码模式{
案例编码(EncodeContainer)
案例解码(解码容器)
}
如果不覆盖枚举本身,则无法更改与枚举相关的值;如果将S
声明为class
,则这是一项非常简单的任务
无论如何,我做了一些实验,我在这里报告:
1) 基于:
2) 声明用于隐式覆盖枚举的变异func
struct S {
var a = 1
}
enum E {
case s(S)
mutating func setS(val:S) { self = E.s(val) }
}
var e = E.s(S(a: 1))
e.setS(val: S(a: 2))
print(2)
3) 如果S
是类
:
class S:CustomDebugStringConvertible {
var a = 1
var debugDescription: String { return "\(a)" }
}
enum E {
case s(S)
}
let e = E.s(S())
if case let .s(s) = e {
s.a = 2
}
print(e)
你到底为什么需要它“到位”?对于值类型,执行读-修改-写操作与就地操作具有相同的语义。您可以在对本地副本进行变异后分配e=.s
。在Swift中,您可以尝试使用UnsafemeutablePointer
moveAssign(from:count:)
。但是,您仍然需要值的地址,并且需要构造一个新值(或子组件)。从反汇编代码来看,与读-修改-写方法相比,似乎不值得这么做。如果你试图解决一些奇特的问题,比如在枚举中有一个pthRead互斥体,你需要手动初始化和销毁,这可能希望你回到C++。这将用一个新的e
值覆盖e
,方法与e=e.s(s(a:2))
相同。是的,它会。但是我改变了值,而不是指针。在我的控制台上:0x00007fbe355083c0
s(TestMutate.ViewController.s(a:2))
0x00007fbe355083c0
你是如何得到那个地址的?打印(\($0)”
我看不出带不可更改指针(to:&e,{$0.pointee=e.s(a:2))
和e=e.s(a:2))
。两者都创建一个新的E
值并将其分配给E
。
class S:CustomDebugStringConvertible {
var a = 1
var debugDescription: String { return "\(a)" }
}
enum E {
case s(S)
}
let e = E.s(S())
if case let .s(s) = e {
s.a = 2
}
print(e)