7

我有一个有点像这样的快速结构:

struct LogicalState {
  let a: String?
  let b: Bool
  let c: Int
}

以及此状态的可变实例。注意状态中的属性都是 all let,所以结构体本身是不可变的。

var _state: LogicalState

我想做的是强制执行允许更新状态的模式,但所有更新都必须是原子的 - 我不想简单地使 a、b 和 c 可变,因为这将允许 a 和 b 独立更改. 我需要控制更新并应用验证(例如,强制执行如果您更改a,您也必须同时更改b

我可以通过简单地覆盖整个结构来做到这一点

_state = LogicalState(a: "newA", b: false, c: _state.c)

但是,如您所见,必须为不变的属性显式引用旧状态 ( _state.c) 是烦人且有问题的,尤其是当您有更多属性时。我的真实示例有 10 个。

在 kotlin 中,它们具有公开“复制”方法的“数据类”,它允许您仅更改所需的参数。如果 swift 支持这样的事情,语法应该是这样的

func copy(a: String? = self.a, b:Bool = self.b, c:Int = self.c) ...

问题是,= self.aswift 中不存在语法,我不确定我还有哪些其他选项?

任何有关如何解决此问题的解决方案将不胜感激

4

2 回答 2

13

想一想,您可以使用 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")
于 2018-05-13T23:23:35.743 回答
3

另一种选择是使用构建器:

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 { $0.a = nil }

然后我们就不必处​​理 Orion Edwards提到的双重选项。

于 2020-07-09T15:23:32.777 回答