如何轻松复制 swift 中的不可变结构,仅改变某些字段 [如 kotlin 数据类复制方法]?
How can I easily copy an immutable struct in swift, varying only some fields [Like kotlin dataclass copy method]?
我有一个 swift 结构有点像这样:
struct LogicalState {
let a: String?
let b: Bool
let c: Int
}
和这个状态的一个可变实例。请注意,状态中的属性都是 let
,因此结构本身是不可变的。
var _state: LogicalState
我想做的是强制执行允许更新状态的模式,但所有更新都必须是原子的——我不想简单地使 a、b 和 c 可变,因为那样会允许b 独立改变。我需要控制更新并应用验证(例如,强制执行如果您更改 a
,您还必须同时更改 b
)
我可以通过简单地覆盖整个结构来做到这一点
_state = LogicalState(a: "newA", b: false, c: _state.c)
但是,如您所见,必须显式引用未更改的属性的旧状态 (_state.c
) 很烦人且存在问题,尤其是当您拥有更多属性时。我的真实示例有 10.
在 kotlin 中,他们有 "data classes" 公开了一个 "copy" 方法,它可以让你只改变你想要的参数。如果 swift 支持这样的东西,语法将如下所示
func copy(a: String? = self.a, b:Bool = self.b, c:Int = self.c) ...
问题是,swift 中不存在 = self.a
语法,我不确定我还有哪些其他选项?
任何关于如何解决这个问题的解决方案都将不胜感激
想一想,您可以使用 copy(...) 方法扩展结构,将 nil 值作为默认值并用实例值替换它们,否则使用非 nil。例如。像这样:
extension LogicalState {
func copy(a: String? = nil, b: Bool? = nil, c: Int? = nil) -> LogicalState {
return LogicalState(a: a ?? self.a, b: b ?? self.b, c: c ?? self.c)
}
}
因此您可以使用它来复制实例,同时改变所需的参数:
let state = LogicalState(a: "A", b: false, c: 10)
let stateCopy1 = state.copy(c: 30)
let stateCopy2 = state.copy(a: "copy 2")
另一种选择是使用构建器:
struct LogicalState {
let a: String?
let b: Bool
let c: Int
}
extension LogicalState {
func copy(build: (inout Builder) -> Void) -> LogicalState {
var builder = Builder(state: self)
build(&builder)
return builder.toLogicalState()
}
struct Builder {
var a: String?
var b: Bool
var c: Int
fileprivate init(state: LogicalState) {
self.a = state.a
self.b = state.b
self.c = state.c
}
fileprivate func toLogicalState() -> LogicalState {
return LogicalState(a: a, b: b, c: c)
}
}
}
let state = LogicalState(a: "a", b: true, c: 0)
let nextState = state.copy { [=10=].a = nil }
那么我们就不必像Orion Edwards.
提到的那样处理双重可选
我有一个 swift 结构有点像这样:
struct LogicalState {
let a: String?
let b: Bool
let c: Int
}
和这个状态的一个可变实例。请注意,状态中的属性都是 let
,因此结构本身是不可变的。
var _state: LogicalState
我想做的是强制执行允许更新状态的模式,但所有更新都必须是原子的——我不想简单地使 a、b 和 c 可变,因为那样会允许b 独立改变。我需要控制更新并应用验证(例如,强制执行如果您更改 a
,您还必须同时更改 b
)
我可以通过简单地覆盖整个结构来做到这一点
_state = LogicalState(a: "newA", b: false, c: _state.c)
但是,如您所见,必须显式引用未更改的属性的旧状态 (_state.c
) 很烦人且存在问题,尤其是当您拥有更多属性时。我的真实示例有 10.
在 kotlin 中,他们有 "data classes" 公开了一个 "copy" 方法,它可以让你只改变你想要的参数。如果 swift 支持这样的东西,语法将如下所示
func copy(a: String? = self.a, b:Bool = self.b, c:Int = self.c) ...
问题是,swift 中不存在 = self.a
语法,我不确定我还有哪些其他选项?
任何关于如何解决这个问题的解决方案都将不胜感激
想一想,您可以使用 copy(...) 方法扩展结构,将 nil 值作为默认值并用实例值替换它们,否则使用非 nil。例如。像这样:
extension LogicalState {
func copy(a: String? = nil, b: Bool? = nil, c: Int? = nil) -> LogicalState {
return LogicalState(a: a ?? self.a, b: b ?? self.b, c: c ?? self.c)
}
}
因此您可以使用它来复制实例,同时改变所需的参数:
let state = LogicalState(a: "A", b: false, c: 10)
let stateCopy1 = state.copy(c: 30)
let stateCopy2 = state.copy(a: "copy 2")
另一种选择是使用构建器:
struct LogicalState {
let a: String?
let b: Bool
let c: Int
}
extension LogicalState {
func copy(build: (inout Builder) -> Void) -> LogicalState {
var builder = Builder(state: self)
build(&builder)
return builder.toLogicalState()
}
struct Builder {
var a: String?
var b: Bool
var c: Int
fileprivate init(state: LogicalState) {
self.a = state.a
self.b = state.b
self.c = state.c
}
fileprivate func toLogicalState() -> LogicalState {
return LogicalState(a: a, b: b, c: c)
}
}
}
let state = LogicalState(a: "a", b: true, c: 0)
let nextState = state.copy { [=10=].a = nil }
那么我们就不必像Orion Edwards.
提到的那样处理双重可选