120

我对 Swift 很陌生,我刚刚读到类是通过引用传递的,而数组/字符串等是被复制的。

通过引用传递是否与在 Objective-C 或 Java 中实际传递“a”引用的方式相同,还是按引用传递是正确的?

4

9 回答 9

190

Swift 中的事物类型

规则是:

  • 类实例是引用类型(即对类实例的引用实际上是一个指针

  • 函数是引用类型

  • 其他一切都是值类型;“其他一切”只是指结构实例和枚举实例,因为这就是 Swift 中的全部内容。例如,数组和字符串是结构实例。正如 newacct 所指出的,您可以通过使用和获取地址来传递对其中一个事物的引用(作为函数参数) 。inout但是类型本身就是一个值类型。

参考类型对您意味着什么

引用类型对象在实践中是特殊的,因为:

  • 仅仅赋值或传递给函数可以产生对同一个对象的多个引用

  • 对象本身是可变的,即使对它的引用是一个常量(let无论是显式的还是隐含的)。

  • 对对象的突变会影响该对象,正如所有对它的引用所看到的那样。

这些可能是危险的,所以要小心。另一方面,传递引用类型显然是有效的,因为只复制和传递了一个指针,这是微不足道的。

价值类型对您意味着什么

显然,传递一个值类型是“更安全的”,let这意味着它所说的:你不能通过let引用来改变结构实例或枚举实例。另一方面,安全性是通过制作价值的单独副本来实现的,不是吗?这不会使传递值类型可能很昂贵吗?

嗯,是的,也不是。它并不像你想象的那么糟糕。正如 Nate Cook 所说,传递值类型并不一定意味着复制,因为let(显式或隐式)保证不变性,因此无需复制任何内容。甚至传递到var引用并不意味着复制事物,只是在必要时可以复制它们(因为存在突变)文档特别建议您不要扭曲内裤。

于 2014-12-08T20:11:17.487 回答
62

默认情况下,Swift 中的所有内容都是通过“复制”传递的,所以当你传递一个值类型时,你会得到一个值的副本,而当你传递一个引用类型时,你会得到一个引用的副本,这意味着。(也就是说,引用的副本仍然指向与原始引用相同的实例。)

我在上面的“复制”周围使用了吓人的引号,因为 Swift 做了很多优化;只要有可能,它就不会复制,直到发生突变或可能发生突变。由于默认情况下参数是不可变的,这意味着大多数情况下实际上不会发生复制。

于 2014-12-08T18:19:47.313 回答
45

当参数不是时,它总是 按值传递inout

如果参数为,则始终是 按引用传递inout。但是,这有点复杂,因为您需要&在传递给参数时显式地在参数上使用运算符inout,因此它可能不符合直接传递变量的传统引用传递定义。

于 2014-12-08T20:02:13.583 回答
12

这是一个通过引用传递的小代码示例。避免这样做,除非你有充分的理由这样做。

func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
    value1 = "my great computation 1";
    value2 = 123456;
}

像这样称呼它

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
于 2017-11-14T18:00:43.087 回答
7

Apple Swift 开发人员博客有一篇名为Value and Reference Types的文章,对这个主题进行了清晰而详细的讨论。

去引用:

Swift 中的类型属于以下两类之一:第一,“值类型”,其中每个实例都保留其数据的唯一副本,通常定义为结构、枚举或元组。第二种,“引用类型”,实例共享数据的一个副本,类型通常定义为一个类。

Swift 博客文章继续通过示例解释差异,并建议您何时使用其中一个。

于 2015-08-04T19:36:52.430 回答
2

当您将 inout 与 += 等中缀运算符一起使用时,可以忽略 &address 符号。我猜编译器假设通过引用传递?

extension Dictionary {
    static func += (left: inout Dictionary, right: Dictionary) {
        for (key, value) in right {
            left[key] = value
        }
    }
}

origDictionary += newDictionaryToAdd

很好的是,这本字典“添加”也只对原始参考进行了一次写入,非常适合锁定!

于 2019-04-16T00:01:47.323 回答
2

类和结构

结构和类之间最重要的区别之一是结构在代码中传递时总是被复制,但类是通过引用传递的。

闭包

如果您将闭包分配给类实例的属性,并且闭包通过引用实例或其成员来捕获该实例,您将在闭包和实例之间创建一个强引用循环。Swift 使用捕获列表来打破这些强引用循环

ARC(自动引用计数)

引用计数仅适用于类的实例。结构和枚举是值类型,而不是引用类型,并且不是通过引用存储和传递的。

于 2019-08-14T05:26:36.660 回答
1

默认情况下,类通过引用传递,其他类通过值传递。inout您可以使用关键字通过引用传递。

于 2017-11-01T13:36:17.757 回答
0

Swift assignpass以及return通过引用reference type复制的值Value Type

[值与参考类型]

如果与您比较,Java您可以找到匹配项:

  • Java 引用类型(所有对象)
  • Java 原始类型(int, bool...) - Swift 使用它扩展它struct
于 2020-11-21T14:52:40.410 回答