在 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 部分。