就地改变值类型关联值

Mutate a value-type associated value in-place

是否可以在 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
   // I want to mutate e in-place
   s.a = 2 
} 

注意: 这似乎是可能的,至少对于 Optional 枚举 s?.a = 2 突变 Optional<S>.


用例:

我正在围绕 Codable 编写一个小型包装器,以便轻松地在字典和对象之间映射值。我有一个 MappingContext,它是 encodedecode。鉴于 KeyedEncodingContainer 在编码时有一个变异函数,我希望这个包装器的用户避免重新分配值,而直接改变关联的值。

我打开了 swift stdlib 代码,该函数甚至没有改变结构,但被标记为正在改变。不知道为什么,但我现在可以毫无问题地获得副本,但重新分配也是一个可以接受的解决方案,只是想确保我没有遗漏任何明显的东西。

typealias EncodeContainer = KeyedEncodingContainer<JsonCodingKey>
typealias DecodeContainer = KeyedDecodingContainer<JsonCodingKey>


public enum CodingMode {
    case encode(EncodeContainer)
    case decode(DecodeContainer)
}

不可能在不覆盖枚举本身的情况下更改枚举关联值;如果相反 S 被声明为 class,这是一个非常微不足道的任务。

无论如何,我做了一些我在这里报告的实验:

1) 基于withUnsafeMutablePointer:

var e = E.s(S(a: 1))
withUnsafeMutablePointer(to: &e, {
   [=10=].pointee = E.s(S(a: 2))
})
print(e)

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) 如果 Sclass:

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)