Is Swift Pass By Value or Pass By Reference

2018-12-31 14:07发布

问题:

I\'m really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.

Is the pass by reference the same way as in Objective-C or Java wherein you actually pass \"a\" reference or is it proper pass by reference?

回答1:

Types of Things in Swift

The rule is:

  • Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)

  • Functions are reference types

  • Everything else is a value type; \"everything else\" simply means instances of structs and instances of enums, because that\'s all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using inout and taking the address, as newacct has pointed out. But the type is itself a value type.

What Reference Types Mean For You

A reference type object is special in practice because:

  • Mere assignment or passing to function can yield multiple references to the same object

  • The object itself is mutable even if the reference to it is a constant (let, either explicit or implied).

  • A mutation to the object affects that object as seen by all references to it.

Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.

What Value Types Mean For You

Clearly, passing a value type is \"safer\", and let means what it says: you can\'t mutate a struct instance or enum instance through a let reference. On the other hand, that safety is achieved by making a separate copy of the value, isn\'t it? Doesn\'t that make passing a value type potentially expensive?

Well, yes and no. It isn\'t as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let (explicit or implied) guarantees immutability so there\'s no need to copy anything. And even passing into a var reference doesn\'t mean that things will be copied, only that they can be if necessary (because there\'s a mutation). The docs specifically advise you not to get your knickers in a twist.



回答2:

It is always pass-by-value when the parameter is not inout.

It is always pass-by-reference if the parameter is inout. However, this is somewhat complicated by the fact you need to explicitly use the & operator on the argument when passing to an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.



回答3:

Everything in Swift is passed by \"copy\" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)

I use scare quotes around the \"copy\" above because Swift does a lot of optimization; wherever possible, it doesn\'t copy until there\'s a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.



回答4:

The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.

To quote:

Types in Swift fall into one of two categories: first, “value types”, where each instance keeps a unique copy of its data, usually defined as a struct, enum, or tuple. The second, “reference types”, where instances share a single copy of the data, and the type is usually defined as a class.

The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.



回答5:

Here is a small code sample for passing by reference. Avoid doing this, unless you have a strong reason to.

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

Call it like this

var val1: String = \"\";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);


回答6:

Classes are passed by references and others are passed by value in default. You can pass by reference by using the inout keyword.