访问作为`inout`传递的`var`是未定义的行为?

时间:2017-09-14 04:37:37

标签: swift pass-by-reference semantics swift4 inout

来自documentation for inout parameters

  

输入输出参数传递如下:

     
      
  1. 调用该函数时,将复制参数的值。
  2.   
  3. 在功能正文中,副本被修改。
  4.   
  5. 当函数返回时,副本的值将分配给原始参数。
  6.   

从这个描述中,我认为修改作为inout参数传递的变量,在它作为inout传递的范围内,是没有意义的,因为原始变量是有保证的在呼叫返回后被覆盖。作为一个人为的例子:

var x: Int = 5

({ (inoutX: inout Int) in
    inoutX = 7
    x = 6
})(&x)

print(x) // Expecting "7"

可以通过变异捕获来访问原始变量x,因此仍可以将其分配给。预期的打印输出为“7”,因为这是函数调用结束时inoutX的值。但是如果我在Swift 4 REPL中运行它,我实际上得到“6”!

该文档阐明了这种行为:

  

作为优化,当参数是存储在内存中物理地址的值时,在函数体内部和外部都使用相同的内存位置。

但接下来是一个非常明显不准确的声明:

  

优化的行为称为引用调用;它满足了拷入式拷贝模型的所有要求,同时消除了复制的开销。

显然,优化的行为不满足inout参数声称符合的值调用结果约定。然后文档确认了这一点,但反过来说明了为什么不应该依赖 call-by-reference 行为:

  

使用copy-in copy-out给出的模型编写代码,而不依赖于逐个引用的优化,以便在优化或不优化的情况下它都能正常运行。

     

不要访问作为输入输出参数传递的值,即使原始参数在当前范围内可用。当函数返回时,对原始文件的更改将被副本的值覆盖。不要依赖于引用调用优化的实现来试图防止更改被覆盖。

我可以收集的是,inout参数是按值调用的结果,除非它们是按引用调用的。而且,根据文档不希望您依赖于引用调用语义的程度,我只能猜测优化不是在明确定义的情况下执行的。如果是这种情况,那么我只能得出结论,访问作为inout参数传递的变量,在inout的范围内,是未定义的行为。

这是一个相对不幸的结论,我对如何不愿意制作文档感到困惑。为什么它会尝试将inout参数表示为遵守特定的调用约定,当(除了setter或属性观察者)之外,这些调用约定的语义不能以定义的方式被观察到?令人困惑的是,我在这里怀疑自己的结论,所以问题就出现了:我的理解是否正确?

0 个答案:

没有答案