使用inout关键字:参数是传引用还是copy-in copy-out(/call by value result)

Using inout keyword: is the parameter passed-by-reference or by copy-in copy-out (/call by value result)

问题: 根据下面的信息和讨论: inout 参数是 passed-by-reference 还是 通过拷入拷出?


基于以下SO线程,inout关键字标记的函数参数按引用传递:

我们注意到最上面的两个线程是 Swift 2.0 之前的;我没能在 SO 上找到关于这个主题的任何更新的讨论(除了有点相关的第三个线程 link)。


根据 Apple 的文档(据我所知),但是,inout 关键字标记的函数参数通过 copy-in copy-out(或按值调用结果

In-out parameters are passed as follows:

When the function is called, the value of the argument is copied. In the body of the function, the copy is modified. When the function returns, the copy’s value is assigned to the original argument. This behavior is known as copy-in copy-out or call by value result. ...

... You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value. ...


现在以我自己的例子为例,试图对此进行调查:

struct MyStruct {
    private var myInt: Int

    mutating func increaseMyInt() {
        myInt++
    }

    func printMyInt() {
        print(String(myInt))
    }

    init(int: Int) {
        myInt = int
    }
}

class MyClass {
    var myStruct: MyStruct

    init(int: Int) {
        myStruct = MyStruct(int: 1)
    }

    func printMyStructsInt() {
        print(String(myStruct.printMyInt()))
    }
}

func myInOutFunc(inout myLocalStruct: MyStruct, myClass: MyClass) -> Int {
    myClass.printMyStructsInt() // prints "1", OK
    myLocalStruct.increaseMyInt()
    myClass.printMyStructsInt() // prints "2": so myStruct is not a copy here?
    myLocalStruct.increaseMyInt()

    return 0
        // according to Apple's doc, shouldn't myStruct member of myClass get
        // assigned (copy of) value of myLocalStruct at this point, and not
        // prior to this?
}

var a = MyClass(int: 1)

a.printMyStructsInt() // prints "1", OK
myInOutFunc(&a.myStruct, myClass: a)
a.printMyStructsInt() // prints "3", OK

这个例子意味着 inout 参数确实是通过引用传递的(正如上面两个 linked SO 线程中所指出的)。由于我们在 inout 参数前加上一个符号 (&),这符合 "feel" 逻辑。

尽最大努力确保我的示例具有代表性---因为这里 inout 参数 myLocalStruct 被发送为 class 属性---我还确保 myLocalStruct 没有得到一些 "behind-the-hood" 参考,因为它是 class 属性:

// ... add to bottom of the code above

func testSendStructAsPublicClassProperty(var myLocalStruct: MyStruct) {
    myLocalStruct.increaseMyInt()
}

// test that sending class property doesn't "reference" things up
a.printMyStructsInt() // prints "3"
testSendStructAsPublicClassProperty(a.myStruct)
a.printMyStructsInt() // prints "3", OK (only copy of class property is sent)

好的,myLocalStruct 在这个例子中确实是函数局部的,因此按值传递(没有引用背后的引擎盖)。


结果: 鉴于上述,inout 参数通过引用传递?

我有两个可能的后续问题:

  1. 我是不是误解了Apple语言文档中关于inout的描述,它可以解释为"pass by reference"吗?
  2. 或者,我的例子还不能代表这个案例吗?

语言参考中接下来的两段对其进行了更详细的描述:

In-Out Parameters

This behavior is known as copy-in copy-out or call by value result. For example, when a computed property or a property with observers is passed as an in-out parameter, its getter is called as part of the function call and its setter is called as part of the function return.

As an optimization, when the argument is a value stored at a physical address in memory, the same memory location is used both inside and outside the function body. The optimized behavior is known as call by reference; it satisfies all of the requirements of the copy-in copy-out model while removing the overhead of copying. Do not depend on the behavioral differences between copy-in copy-out and call by reference.

事实上"pass by reference"