Swift通过价值或通过参考传递

gra*_*aci 92 pass-by-reference pass-by-value pass-by-pointer swift

我是Swift的新手,我只是读取类通过引用传递,数组/字符串等被复制.

通过引用传递的方式与Objective-C或Java中的方式相同,其中您实际传递"a"引用或是否通过引用正确传递?

mat*_*att 156

斯威夫特的事物类型

规则是:

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

  • 函数是引用类型

  • 其他一切都是价值类型 ; "其他一切"只是意味着结构和枚举实例的实例,因为这就是Swift的全部内容.例如,数组和字符串是结构实例.正如newacct指出的那样,您可以通过使用inout和获取地址传递对这些事物之一的引用(作为函数参数).但类型本身就是一种价值类型.

什么参考类型对您意味着什么

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

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

  • 即使对它的引用是常量(let显式或隐含),对象本身也是可变的.

  • 对象的变异会影响该对象,如所有对它的引用所见.

那些可能是危险的,所以要留意.另一方面,传递引用类型显然是有效的,因为只复制并传递指针,这是微不足道的.

什么价值类型对你意味着什么

显然,传递值类型是"更安全",并且let意味着它所说的内容:您不能通过let引用来改变结构实例或枚举实例.另一方面,安全是通过单独复制价值来实现的,不是吗?这是否会使传递值类型的代价变得昂贵?

嗯,是的,不.它没有你想象的那么糟糕.正如Nate Cook所说,传递值类型并不一定意味着复制,因为let(明示或暗示)保证不变性,因此不需要复制任何东西.甚至突入var参考并不意味着事情被复制,只有他们可以是如果需要的话(因为有一个突变).文档特别建议你不要让你的短裤扭曲.

  • 对,值类型/引用类型不应与传值/传递引用相混淆,因为值类型可以通过值或引用传递,引用类型也可以通过值或引用传递. (5认同)
  • "类实例通过引用传递.函数通过引用传递"Nope.无论类型如何,当参数不是"inout"时,它都是值传递.某些东西是否通过引用是与类型正交的. (4认同)
  • @newacct嗯,当然你严格意义上说是对的!严格来说,应该说一切都是按值传递,但枚举实例和结构实例是_value types_,而类实例和函数是_reference types_.例如,请参阅https://developer.apple.com/swift/blog/?id=10 - 另请参阅https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures. html#// apple_ref/doc/uid/TP40014097-CH13-XID_145但是,我认为我所说的符合一般意义上的意思. (3认同)

new*_*cct 41

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

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

  • `inout`实际上不是通过引用传递而是_copy-in copy-out_它只保证在函数调用后修改后的值将被赋值给原始参数.[In-Out Parameters](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545) (7认同)
  • 这个答案与Nate Cook的答案结合在一起(对我来说更清晰)(来自C ++),因为即使“引用类型”也将*不会*在函数范围之外被修改,除非*您显式指定(使用`inout`)。 ) (2认同)
  • 尽管确实一切都是按值传递的。当副本引用同一实例时,可以在函数内部修改引用类型属性。 (2认同)

Nat*_*ook 36

默认情况下,Swift中的所有内容都通过"复制"传递,因此当您传递值类型时,您将获得该值的副本,并且当您传递引用类型时,您将获得引用的副本,其中包含所有含义.(也就是说,引用的副本仍然指向与原始引用相同的实例.)

我在上面的"副本"周围使用了恐慌引用,因为Swift做了很多优化; 只要有可能,它就不会复制,直到出现突变或突变的可能性.由于默认情况下参数是不可变的,这意味着大多数情况下实际上没有复制.

  • 对我来说,这是最好的答案,因为它澄清了例如实例属性可以在函数内部修改,即使参数是副本(按值传递),因为它指向相同的引用。 (2认同)

Chr*_*ckx 7

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

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

像这样称呼它

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
Run Code Online (Sandbox Code Playgroud)

  • 这不会通过引用传递。`inout` 是一个复制入、复制出运算符。它会首先复制对象,然后在函数返回后覆盖原始对象。虽然看起来相同,但存在细微的差异。 (4认同)
  • @Brainless,因为它增加了代码不必要的复杂性。最好接收参数并返回单个结果。必须这样做通常表明设计不佳。另一种说法是,传入的引用变量中隐藏的副作用对于调用者来说是不透明的。 (2认同)

why*_*ite 6

苹果斯威夫特开发者博客有一个叫后的价值和引用类型,提供有关这个题目的明确和详细的讨论.

报价:

Swift中的类型分为两类:第一类是"值类型",其中每个实例都保留其数据的唯一副本,通常定义为struct,enum或tuple.第二种是"引用类型",其中实例共享数据的单个副本,并且类型通常被定义为类.

Swift博客文章继续解释与示例的差异,并建议何时使用一个而不是另一个.

  • 这并不能回答问题。问题是关于值传递与引用传递,这与值类型与引用类型完全正交。 (3认同)