使用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
关键字标记的函数参数按引用传递:
- Is Swift Pass By Value or Pass By Reference
- Why doesn't inout pass by reference?
我们注意到最上面的两个线程是 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
参数通过引用传递?
我有两个可能的后续问题:
- 我是不是误解了Apple语言文档中关于
inout
的描述,它可以解释为"pass by reference"吗?
- 或者,我的例子还不能代表这个案例吗?
语言参考中接下来的两段对其进行了更详细的描述:
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"
问题: 根据下面的信息和讨论: inout
参数是 passed-by-reference 还是 通过拷入拷出?
基于以下SO线程,inout
关键字标记的函数参数按引用传递:
- Is Swift Pass By Value or Pass By Reference
- Why doesn't inout pass by reference?
我们注意到最上面的两个线程是 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
参数通过引用传递?
我有两个可能的后续问题:
- 我是不是误解了Apple语言文档中关于
inout
的描述,它可以解释为"pass by reference"吗? - 或者,我的例子还不能代表这个案例吗?
语言参考中接下来的两段对其进行了更详细的描述:
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"