Inout in swift和reference类型

时间:2018-05-09 19:36:28

标签: swift reference inout

我试图理解值和引用类型之间的区别。现在我想使用苹果指南中的功能:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
  let temporaryA = a
  a = b
  b = temporaryA
}

如果我想使用这个函数我将编写此代码

swapTwoInts{&firstIntStruct, &secondIntStruct}

据我所知,我们必须在此函数中引入类型,但Int是值类型,因此我们使用&。
另一方面,当我尝试在交换函数中将Int更改为我的类时,我也必须写&在我班级的实例之前。

为什么我必须这样做,如果它已经是参考?

3 个答案:

答案 0 :(得分:2)

假设我们编写了您正在谈论的假设函数:

class C {}

func swapTwoC(_ lhs: C, rhs: C) {
    let originalLHS = lhs
    lhs = rhs
    rhs = originalLHS
}

当前的问题是lhsrhs是不可变的。要改变它们,我们需要制作可变副本:

func swapTwoC(_ lhs: C, rhs: C) {
    var lhs = lhs; var rhs = rhs
    let originalLHS = lhs
    lhs = rhs
    rhs = originalLHS
}

但现在问题是我们正在改变我们的副本,而不是我们的来电者给我们的原始参考。

更基本的是,问题在于当您将引用(对于我们称之为对象的类的实例)传递给函数时,将复制引用本身(它的行为类似于值类型)。如果该函数改变了引用的值,它只会改变它自己的本地副本,正如我们所看到的那样。

如果您有inout C,并且传递了&myObject,那么您实际传入的内容是myObject 。复制函数参数时,复制的是"参考ref"。然后,该函数可以使用"参考ref"为调用者具有的引用myObject分配新值

答案 1 :(得分:1)

所以有一些较低级别的内存组件可以充分发挥作用。

1)创建值或引用类型时,堆栈上有一个新变量。该变量可以是值类型的实际数据,也可以是引用类型的数据指针。

2)当你调用一个函数时,它会创建一个新的堆栈部分,并在堆栈上创建新的变量(swift中的let个实例),复制传入的变量。所以对于值类型它会执行深层复制,对于引用类型,它会复制指针。

所以这意味着当您使用inout时,请使用此变量的内存地址并更新其包含的数据。因此,您可以为值类型新数据或引用类型提供新的指针地址,它将在交换函数范围之外更改。它使var(与传入的内容相同)代替let,就像正常一样。

答案 2 :(得分:1)

我想用例子解释一下。正如@Alexander所提到的,对于Int作为参数的函数:

  

<强> 1。按值传递

     

它会改变副本,而不是调用者的原始引用。

     

更基本的是,问题在于当您将引用(对于我们称之为对象的类的实例)传递给函数时,将复制引用本身(它的行为类似于值类型)。如果该函数改变了引用的值,它只会改变它自己的本地副本,正如我们所看到的那样。

enter image description here

你可以看到

func swapTwoInts(_ a: Int, _ b: Int) { }

如果更改了 p和q 的值,则 self.x和self.y 保持不变。由于此函数传递 x和y 的值而不是它们的引用。

  

<强> 2。通过引用传递:

func swapTwoInts(_ a: inout Int, _ b: inout Int) { }

它传递了 self.x和self.y 的引用,这就是为什么你不必再像以前那种类型中的p和q那样改变它们。因为它会使用var xvar y变异对象。

您可以看到,a和b具有日志中的引用值,并且更改 a和b 也更改了 self.x和self.y ,因为和b具有相同的x和y的引用(地址)。

enter image description here