我不是 Swift 程序员,所以我对这门语言一无所知。我只是出于好奇才问。我遇到了一种语言构造,其中变异函数内部被分配了一个新值,如下例中的self函数所示。moveByAssigmentToSelf
struct Point {
var x = 0.0
var y = 0.0
mutating func moveByAssigmentToSelf(_ deltaX: Double, _ deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
mutating func moveByMutatingMembers(_ deltaX: Double, _ deltaY: Double) {
self.x += deltaX
self.y += deltaY
}
}
Run Code Online (Sandbox Code Playgroud)
来自 C/C++/Java/C# 背景,我认为它是self指向内存中某处(例如堆栈上)的结构值(开始)的指针(地址)。this对我来说,分配给C++ 结构中应该等效的东西看起来很奇怪。AFAICT,该函数moveByMutatingMembers应该具有观察上等效的效果,并且在 C++/Java 世界中是很自然的事情。
有人可以向非 Swift 程序员解释一下这个概念背后的基本原理/想法是什么吗?
我在语言参考(关于表达式的章节)中所能找到的只是以下模糊的陈述:“在初始化器、下标或实例方法中, self 指的是它出现的类型的当前实例。” 和“在值类型的变异方法中,您可以将该值类型的新实例分配给 self。”
我想要理解的是为什么这个分配是一个好主意,与传统的解决方案相比,它解决了哪些编程问题?
换句话说:为什么从语言设计的角度来看这有意义?或者:如果您必须使用 C++/Java 方式进行操作,您会损失什么?
顺便说一句,出于好奇,我查看了这个示例的 Godbolt反汇编,对于我未经训练的眼睛来说,与替代方案相比,输出看起来效率moveByAssigmentToSelf极低。
Rob*_*ier 18
来自 C/C++/Java/C# 背景,我认为 self 是一个指针
这是不正确的。由于此类型是值类型(结构),因此self是该值的副本。的强大mutating之处在于,它将在函数结束时用新值替换以前的值。值没有“实例”。它们只是价值观。
有关 Swift 中值类型的有用介绍,请参阅值和引用类型。Swift 主文档中的“结构和枚举是值类型”也很有用。
Swift 结构有点像 C++,如果你放弃对new指针和引用的先入之见,只考虑结构就是结构。它们作为值(副本)传递,就像 C++ 结构一样。只是在 Swift 中,这是正常的处理方式,与 C++ 不同,C++ 中的事物通常通过引用传递。
对于你关于效率的问题,那只是因为你没有打开优化。通过优化,它们实际上是相同的代码,并且它们内联对以下内容的调用init:
output.Point.moveByAssigmentToSelf(Swift.Double, Swift.Double) -> ():
movupd xmm2, xmmword ptr [r13]
unpcklpd xmm0, xmm1
addpd xmm0, xmm2
movupd xmmword ptr [r13], xmm0
ret
output.Point.moveByMutatingMembers(Swift.Double, Swift.Double) -> ():
jmp (output.Point.moveByAssigmentToSelf(Swift.Double, Swift.Double) -> ())
Run Code Online (Sandbox Code Playgroud)
看看你向@matt提出的问题,我希望这也可以帮助你更好地理解这个系统:
var p: Point = Point(x: 1, y: 2) {
didSet { print("new Point: \(p)")}
}
p.moveByMutatingMembers(1, 2)
Run Code Online (Sandbox Code Playgroud)
这仅打印一次“new Point”,因为p仅被替换(设置)一次。
另一方面:
p.x = 0
p.y = 1
Run Code Online (Sandbox Code Playgroud)
这将打印“新点”两次,因为p被替换了两次。在 Point 上调用变元会将整个值替换为新值。
小智 5
分配 toself很有用,有几个原因,但您的示例没有说明任何原因。+虽然使用and运算符可以更好地拼写+=,但只有当已经存在另一个对新值执行工作的方法时,分配 toself在您的示例中才有意义。
func moved(_ deltaX: Double, _ deltaY: Double) -> Self {
.init(x: x + deltaX, y: y + deltaY)
}
mutating func move(_ deltaX: Double, _ deltaY: Double) {
self = moved(deltaX, deltaY)
}
Run Code Online (Sandbox Code Playgroud)
非变异和变异对的另一个选项将工作切换到变异变体:
func moved(_ deltaX: Double, _ deltaY: Double) -> Self {
var point = self
point.move(deltaX, deltaY)
return point
}
mutating func move(_ deltaX: Double, _ deltaY: Double) {
x += deltaX
y += deltaY
}
Run Code Online (Sandbox Code Playgroud)
请参阅union标准库中的一个实际示例。您对性能的担忧并非没有根据,但您__consuming很快就会发现这些担忧很快就会消失。
| 归档时间: |
|
| 查看次数: |
1381 次 |
| 最近记录: |