在didSet我看到的很多例子中,这个代码会返回0,但是,我不能让它返回除原始值之外的任何东西.我究竟做错了什么?
迅速
struct Circle {
var radius: Double {
didSet {
if radius < 0 {
radius = 0
}
}
}
}
var circ = Circle(radius: -25)
print(circ.radius)
Run Code Online (Sandbox Code Playgroud)
产量
-25
Run Code Online (Sandbox Code Playgroud) Swift编程的普遍共识(截至2018年5月,Swift 4.1,Xcode 9.3)是结构应该是首选,除非您的逻辑明确要求对象的共享引用.
我们知道,结构的一个问题是它们是按值传递的,因此在将结构传递给函数或从函数返回时会产生一个副本.如果你有一个大的结构(比如说有12个属性),那么这种复制可能会变得昂贵.
这通常由人们说,swift编译器和/或LLVM可以删除副本(即传递对结构的引用,而不是复制它),并且只有在实际改变结构时才需要复制.
这一切都很好,但它总是在理论上被谈到 - "作为优化,LLVM 可以忽略副本"和类似的东西.
我的问题是,任何人都可以告诉我们什么实际发生了什么?编译器是否真的忽略了副本,或者它只是一天可能存在的理论上的未来优化?(例如,C#编译器理论上也可以删除struct副本,但它实际上从未实现过,并且Microsoft建议您不要对大于16字节的事物使用结构[1])
如果swift确实存在elide结构副本,那么是否以及何时执行此操作会有一些解释或启发式吗?
注意:我在谈论用户定义的结构,而不是像数组和字典这样的stdlib内置
[1] https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct
让我们假设我们struct在 Swift 中有一个相当大的:
struct SuperStruct {
var field1: Int = 0
var field2: String = ""
// lots of lines...
var field512: Float = 0.0
}
Run Code Online (Sandbox Code Playgroud)
.. 然后我们需要实现Equatable协议:
extension SuperStruct: Equatable {
}
func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {
return
lhs.field1 == rhs.field1 &&
lhs.field2 == rhs.field2 &&
// lots of lines...
lhs.field512 == rhs.field512
}
Run Code Online (Sandbox Code Playgroud)
...我们需要编写大量愚蠢的代码行。有没有办法“要求”编译器为我们“做”它?
我有一个像这样的swift结构:
struct LogicalState {
let a: String?
let b: Bool
let c: Int
}
Run Code Online (Sandbox Code Playgroud)
以及这种状态的可变实例.注意状态中的属性都是let,所以struct本身是不可变的.
var _state: LogicalState
Run Code Online (Sandbox Code Playgroud)
我想要做的是强制执行一种模式,允许更新状态,但所有更新必须是原子的 - 我不想简单地使a,b和c变为可变,因为这将允许a和b独立更改.我需要控制更新并应用验证(例如,要强制执行,如果更改a,您还必须同时更改b)
我可以通过简单地覆盖整个结构来做到这一点
_state = LogicalState(a: "newA", b: false, c: _state.c)
Run Code Online (Sandbox Code Playgroud)
但是,正如您所看到的,必须为不改变的属性显式引用旧状态(_state.c)是烦人且有问题的,尤其是当您有更多属性时.我的真实世界的例子有10个.
在kotlin中,他们有"数据类",它们公开了一个"复制"方法,它允许你只改变你想要的参数.如果swift支持这样的东西,语法将如下所示
func copy(a: String? = self.a, b:Bool = self.b, c:Int = self.c) ...
Run Code Online (Sandbox Code Playgroud)
问题是,= self.aswift中不存在语法,我不确定我有哪些其他选项?
如何解决这个问题的任何解决方案将非常感激