Swift4:为什么以及何时同时访问单独的结构元素是非法的?
Swift4: why and when is simultaneous access to separate struct elements illegal?
类似于、
中的情况
I am getting run-time errors (Swift 4.2 Xcode 10.0) for
attempting "simultaneous access" in an object method to two separate
members of a single instance struct.
如果我尝试对两个单独的实例成员进行相同类型的访问(从概念上讲,它们也是单个不同实例结构的两个单独成员:对象本身;即 self),没有问题。任何人都可以帮助我了解我违反的条件及其存在的原因吗?
import Cocoa
struct SomeStruct {
var a:Int = 0
var b:Int = 0
}
func writeTwoValues(first:inout Int, second:inout Int) {
first = 1
second = 2
}
@NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
fileprivate var someStruct = SomeStruct() // Instance struct of ints
var c:Int = 0 // Instance ints not inside a struct
var d:Int = 0
func applicationDidFinishLaunching(_ aNotification: Notification) {
writeTwoValues(first: &c, second: &d) // Works great
writeTwoValues(first: &someStruct.a, second: &someStruct.b)
// Fails at runtime with "Simultaneous accesses..., but modification requires exclusive access
}
}
上面引用的问题的公认响应者写道,独占访问是在这种访问模式中设计的"to prevent you exactly from doing what you're trying to do"。但是 WWDC 视频 和 SE-0176 只包含同一块内存被两个不同的引用别名的示例。我明白为什么这些是有问题的。然而,在上面的代码中,就像在引用的查询中一样,这两个引用针对所有 运行 时间执行路径中的独立且不重叠的内存位置。我们永远不会同时对同一内存或内存重叠部分(例如成员和包含它的结构)进行两次 io 访问。那么,为什么这是设计和 运行时间错误?
(我知道,如果您可以访问结构定义和采用 io 参数的方法,那么重写这些示例是微不足道的。如果您正在访问一个固定的 API,您的选择就更少了。我'我更感兴趣的是理解为什么 Swift 拒绝这个代码,以及法律代码的精确边界在哪里,而不是弄清楚如何让我的样本在这里以不同的方式 运行。)
正如您正确陈述的那样,实际上您的代码中没有访问冲突。问题是 Swift 是否认识到这一点或采取安全措施。
转向 Swift 编程语言 (Swift 4.2),这与我们对 [=44 的正式定义最接近=] 我们在 内存安全 章节中找到:
Conflicting Access to Properties
Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value.
在这里您可以将“因为这些是值类型”读作“在 Swift 中决定对于复合值类型”,即 Apple 做出选择并以这种方式定义事物,其他语言可能会做出其他选择。
因此,根据该声明,您的代码存在冲突。然而,几段之后,Apple 写了关于放宽此规范的文章:
In practice, most access to the properties of a structure can overlap safely.
[An example similar to yours except it uses a local variable]
The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.
所以 Apple 说在 local 变量的情况下,编译器可以确定没有重叠访问并放宽对任何成员的访问被视为对整体的访问的限制.
但是您正在使用 class 的 实例 变量。几段之后 Apple 声明:
Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:
You’re accessing only stored properties of an instance, not computed properties or class properties.
The structure is the value of a local variable, not a global variable.
The structure is either not captured by any closures, or it’s captured only by nonescaping closures.
并且从您的代码中我们可以说这里出现的“,不是全局变量”并不详尽,它意味着除“局部变量”之外的任何其他内容。
当然我说它出现这里因为我们都知道Swift是一个松散定义的移动目标,它的编译器和语义可能会在下周二有所不同; -)
HTH
类似于
I am getting run-time errors (Swift 4.2 Xcode 10.0) for attempting "simultaneous access" in an object method to two separate members of a single instance struct.
如果我尝试对两个单独的实例成员进行相同类型的访问(从概念上讲,它们也是单个不同实例结构的两个单独成员:对象本身;即 self),没有问题。任何人都可以帮助我了解我违反的条件及其存在的原因吗?
import Cocoa
struct SomeStruct {
var a:Int = 0
var b:Int = 0
}
func writeTwoValues(first:inout Int, second:inout Int) {
first = 1
second = 2
}
@NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
fileprivate var someStruct = SomeStruct() // Instance struct of ints
var c:Int = 0 // Instance ints not inside a struct
var d:Int = 0
func applicationDidFinishLaunching(_ aNotification: Notification) {
writeTwoValues(first: &c, second: &d) // Works great
writeTwoValues(first: &someStruct.a, second: &someStruct.b)
// Fails at runtime with "Simultaneous accesses..., but modification requires exclusive access
}
}
上面引用的问题的公认响应者写道,独占访问是在这种访问模式中设计的"to prevent you exactly from doing what you're trying to do"。但是 WWDC 视频 和 SE-0176 只包含同一块内存被两个不同的引用别名的示例。我明白为什么这些是有问题的。然而,在上面的代码中,就像在引用的查询中一样,这两个引用针对所有 运行 时间执行路径中的独立且不重叠的内存位置。我们永远不会同时对同一内存或内存重叠部分(例如成员和包含它的结构)进行两次 io 访问。那么,为什么这是设计和 运行时间错误?
(我知道,如果您可以访问结构定义和采用 io 参数的方法,那么重写这些示例是微不足道的。如果您正在访问一个固定的 API,您的选择就更少了。我'我更感兴趣的是理解为什么 Swift 拒绝这个代码,以及法律代码的精确边界在哪里,而不是弄清楚如何让我的样本在这里以不同的方式 运行。)
正如您正确陈述的那样,实际上您的代码中没有访问冲突。问题是 Swift 是否认识到这一点或采取安全措施。
转向 Swift 编程语言 (Swift 4.2),这与我们对 [=44 的正式定义最接近=] 我们在 内存安全 章节中找到:
Conflicting Access to Properties
Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value.
在这里您可以将“因为这些是值类型”读作“在 Swift 中决定对于复合值类型”,即 Apple 做出选择并以这种方式定义事物,其他语言可能会做出其他选择。
因此,根据该声明,您的代码存在冲突。然而,几段之后,Apple 写了关于放宽此规范的文章:
In practice, most access to the properties of a structure can overlap safely.
[An example similar to yours except it uses a local variable]
The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.
所以 Apple 说在 local 变量的情况下,编译器可以确定没有重叠访问并放宽对任何成员的访问被视为对整体的访问的限制.
但是您正在使用 class 的 实例 变量。几段之后 Apple 声明:
Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:
You’re accessing only stored properties of an instance, not computed properties or class properties.
The structure is the value of a local variable, not a global variable.
The structure is either not captured by any closures, or it’s captured only by nonescaping closures.
并且从您的代码中我们可以说这里出现的“,不是全局变量”并不详尽,它意味着除“局部变量”之外的任何其他内容。
当然我说它出现这里因为我们都知道Swift是一个松散定义的移动目标,它的编译器和语义可能会在下周二有所不同; -)
HTH