在 Swift 中通过引用传递变量
Passing variables by reference in Swift
我开始学习 c++,现在我想知道我是否也可以在 Swift 中做一些事情。
我从来没有真正想过当我们将变量作为参数传递给 Swift 中的函数时会发生什么。
我们以string
类型的变量为例。
在 c++ 中,我可以通过复制它或传递 reference/pointer.
来将参数传递给函数
void foo(string s)
或 void foo (string& s)
;
在第一种情况下,我的原始变量的副本将被创建,foo 将收到一个副本。在第二种情况下,我基本上是在不创建副本的情况下传递内存中变量的地址。
现在在 Swift 我知道我可以将函数的参数声明为 inout,这意味着我可以修改原始对象。
1) func foo(s:String)
...
2) func testPassingByReference(s: inout String)
...
我对 String 进行了扩展以打印对象的地址:
extension String {
func address() -> String {
return String(format: "%p", self);
}
}
结果出乎我的意料。
var str = "Hello world"
print(str.address())
0x7fd6c9e04ef0
func testPassingByValue(s: String) {
print("he address of s is: \(s.address())")
}
func testPassingByReference(s: inout String) {
print("he address of s is: \(s.address())")
}
testPassingByValue(s: str)
0x7fd6c9e05270
testPassingByReference(s: &str)
0x7fd6c9e7caf0
我理解为什么当我们按值传递参数时地址不同,但这不是我在将参数作为 inout 参数传递时所期望看到的。
Apple 开发者网站说
In Swift, Array, String, and Dictionary are all value types.
所以问题是,有什么方法可以避免复制我们传递给函数的对象(我可以有一个相当大的数组或字典)或者 Swift 不允许我们做这样的事?
复制数组和字符串的成本很低(几乎是免费的),只要您不对其进行修改即可。 Swift 在 stdlib 中为这些集合实现写时复制。这不是语言级别的功能;它实际上是为数组和字符串(以及其他一些类型)显式实现的。因此,您可以拥有大型阵列的多个副本,它们都共享相同的后备存储。
inout
和"by reference."不是一回事,字面意思是"in-out."在函数开始处复制值,然后复制回原来的位置结束。
Swift 的方法往往对常见用途具有高性能,但 Swift 并没有像 C++ 那样做出强大的性能承诺。 (也就是说,这使得 Swift 在某些情况下比 C++ 更快,因为 Swift 在数据结构的选择上不受限制。)作为一般规则,我发现它非常很难推断任意 Swift 代码的可能性能。很容易推断最坏情况下的性能(假设复制总是发生),但很难确定何时可以避免复制。
尽管 inout
参数修改了用作函数输入参数的变量,但它们的工作方式与其他语言中的 by reference 并不完全相同。 Swift
中的行为称为copy-in copy-out 或按值结果调用。这意味着当您使用 inout
参数时,在函数调用时,它的值被复制,并且在函数内部,变量的本地副本被修改。在函数 return 时,它用修改后的副本值覆盖 inout
参数原始内存位置的值。
您正在打印函数内部变量的地址,因此您实际上是在打印复制值的位置。尝试在函数 returned 之后打印,您会看到您正在使用修改后的值打印原始位置。
有关详细信息,请参阅文档的 In-Out parameters 部分。
我开始学习 c++,现在我想知道我是否也可以在 Swift 中做一些事情。
我从来没有真正想过当我们将变量作为参数传递给 Swift 中的函数时会发生什么。
我们以string
类型的变量为例。
在 c++ 中,我可以通过复制它或传递 reference/pointer.
来将参数传递给函数void foo(string s)
或 void foo (string& s)
;
在第一种情况下,我的原始变量的副本将被创建,foo 将收到一个副本。在第二种情况下,我基本上是在不创建副本的情况下传递内存中变量的地址。
现在在 Swift 我知道我可以将函数的参数声明为 inout,这意味着我可以修改原始对象。
1) func foo(s:String)
...
2) func testPassingByReference(s: inout String)
...
我对 String 进行了扩展以打印对象的地址:
extension String {
func address() -> String {
return String(format: "%p", self);
}
}
结果出乎我的意料。
var str = "Hello world"
print(str.address())
0x7fd6c9e04ef0
func testPassingByValue(s: String) {
print("he address of s is: \(s.address())")
}
func testPassingByReference(s: inout String) {
print("he address of s is: \(s.address())")
}
testPassingByValue(s: str)
0x7fd6c9e05270
testPassingByReference(s: &str)
0x7fd6c9e7caf0
我理解为什么当我们按值传递参数时地址不同,但这不是我在将参数作为 inout 参数传递时所期望看到的。
Apple 开发者网站说
In Swift, Array, String, and Dictionary are all value types.
所以问题是,有什么方法可以避免复制我们传递给函数的对象(我可以有一个相当大的数组或字典)或者 Swift 不允许我们做这样的事?
复制数组和字符串的成本很低(几乎是免费的),只要您不对其进行修改即可。 Swift 在 stdlib 中为这些集合实现写时复制。这不是语言级别的功能;它实际上是为数组和字符串(以及其他一些类型)显式实现的。因此,您可以拥有大型阵列的多个副本,它们都共享相同的后备存储。
inout
和"by reference."不是一回事,字面意思是"in-out."在函数开始处复制值,然后复制回原来的位置结束。
Swift 的方法往往对常见用途具有高性能,但 Swift 并没有像 C++ 那样做出强大的性能承诺。 (也就是说,这使得 Swift 在某些情况下比 C++ 更快,因为 Swift 在数据结构的选择上不受限制。)作为一般规则,我发现它非常很难推断任意 Swift 代码的可能性能。很容易推断最坏情况下的性能(假设复制总是发生),但很难确定何时可以避免复制。
尽管 inout
参数修改了用作函数输入参数的变量,但它们的工作方式与其他语言中的 by reference 并不完全相同。 Swift
中的行为称为copy-in copy-out 或按值结果调用。这意味着当您使用 inout
参数时,在函数调用时,它的值被复制,并且在函数内部,变量的本地副本被修改。在函数 return 时,它用修改后的副本值覆盖 inout
参数原始内存位置的值。
您正在打印函数内部变量的地址,因此您实际上是在打印复制值的位置。尝试在函数 returned 之后打印,您会看到您正在使用修改后的值打印原始位置。
有关详细信息,请参阅文档的 In-Out parameters 部分。