Ian*_*ton 13 immutability swift
如果我想将我的视图控制器的状态表示为单个结构然后实现撤销机制,那么我如何更改结构上的一个属性,同时获取前一个状态的副本?
struct A {
let a: Int
let b: Int
init(a: Int = 2, b: Int = 3) {
self.a = a
self.b = b
}
}
let state = A()
Run Code Online (Sandbox Code Playgroud)
现在我想要一份state但是b = 4 的副本.如何在不构造新对象且必须为每个属性指定值的情况下执行此操作?
Sha*_* Of 20
请注意,当你使用占位符值常数 a和b你是不是能够构建的情况下A与任何其他值,但这占位符.写初始化器.您可以编写自定义方法来更改struct中的任何值:
struct A {
let a: Int
let b: Int
init(a: Int = 2, b: Int = 3) {
self.a = a
self.b = b
}
func changeValues(a: Int? = nil, b: Int? = nil) -> A {
return A(a: a ?? self.a, b: b ?? self.b)
}
}
let state = A()
let state2 = state.changeValues(b: 4)
Run Code Online (Sandbox Code Playgroud)
如果您可以使用可变属性,那么这是另一种方法。优点是它适用于每个结构,并且无需在添加属性时更改函数:
struct A {
var a: Int
var b: Int
func changing(change: (inout A) -> Void) -> A {
var a = self
change(&a)
return a
}
}
let state = A(a: 2, b: 3)
let nextState = state.changing{ $0.b = 4 }
Run Code Online (Sandbox Code Playgroud)
您也可以对此进行扩展:
protocol Changeable {}
extension Changeable {
func changing(change: (inout Self) -> Void) -> Self {
var a = self
change(&a)
return a
}
}
extension A : Changeable {}
Run Code Online (Sandbox Code Playgroud)
您也可以使用它来执行此操作,而无需任何其他代码:
let nextState = {
var a = state
a.b = 4
return a
}()
Run Code Online (Sandbox Code Playgroud)
如果您不介意新结构是可变的,那只是
var nextState = state
nextState.b = 4
Run Code Online (Sandbox Code Playgroud)
这里的答案很荒谬,尤其是在 struct 的成员发生变化的情况下。
让我们了解 Swift 是如何工作的。
当一个结构体从一个变量设置为另一个变量时,该结构体会自动克隆到新变量中,即相同的结构体彼此不相关。
struct A {
let a: Int
var b: Int
}
let a = A(a: 5, b: 10)
var a1 = a
a1.b = 69
print("a.b = \(a.b); a1.b = \(a1.b)") // prints "a.b = 10; a1.b = 69"
Run Code Online (Sandbox Code Playgroud)
请记住,如果您打算更改结构中的成员,则必须将其标记为“var”而不是“let”。
更多信息在这里:https : //docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
这很好,但是如果您仍然想在一行中进行复制和修改,请将此函数添加到您的结构中:
func change<T>(path: WritableKeyPath<A, T>, to value: T) -> A {
var clone = self
clone[keyPath: path] = value
return clone
}
Run Code Online (Sandbox Code Playgroud)
现在,之前的示例更改为:
let a = A(a: 5, b: 10)
let a1 = a.change(path: \.b, to: 69)
print("a.b = \(a.b); a1.b = \(a1.b)") // prints "a.b = 10; a1.b = 69"
Run Code Online (Sandbox Code Playgroud)
我看到向很多结构添加“更改”会很痛苦,但扩展会很棒:
protocol Changeable {}
extension Changeable {
func change<T>(path: WritableKeyPath<Self, T>, to value: T) -> Self {
var clone = self
clone[keyPath: path] = value
return clone
}
}
Run Code Online (Sandbox Code Playgroud)
使用“Changeable”扩展您的结构,您将拥有“change”功能。
| 归档时间: |
|
| 查看次数: |
7510 次 |
| 最近记录: |