When to use inout parameters?

前端 未结 7 1578
情书的邮戳
情书的邮戳 2020-12-13 03:15

When passing a class or primitive type into a function, any change made in the function to the parameter will be reflected outside of the class. This is basically the same t

相关标签:
7条回答
  • 2020-12-13 03:47

    Basically it is useful when you want to play with addresses of variable its very useful in data structure algorithms

    0 讨论(0)
  • 2020-12-13 03:50

    Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

    0 讨论(0)
  • 2020-12-13 03:57

    From Apple Language Reference: Declarations - In-Out Parameters:

    As an optimization, when the argument is a value stored at a physical address in memory, the same memory location is used both inside and outside the function body. The optimized behavior is known as call by reference; it satisfies all of the requirements of the copy-in copy-out model while removing the overhead of copying. Do not depend on the behavioral differences between copy-in copy-out and call by reference.

    If you have a function that takes a somewhat memory-wise large value type as argument (say, a large structure type) and that returns the same type, and finally where the function return is always used just to replace the caller argument, then inout is to prefer as associated function parameter.

    Consider the example below, where comments describe why we would want to use inout over a regular type-in-return-type function here:

    struct MyStruct {
        private var myInt: Int = 1
    
        // ... lots and lots of stored properties
    
        mutating func increaseMyInt() {
            myInt += 1
        }
    }
    
    /* call to function _copies_ argument to function property 'myHugeStruct' (copy 1)
       function property is mutated
       function returns a copy of mutated property to caller (copy 2) */
    func myFunc(var myHugeStruct: MyStruct) -> MyStruct {
        myHugeStruct.increaseMyInt()
        return myHugeStruct
    }
    
    /* call-by-reference, no value copy overhead due to inout opimization */
    func myFuncWithLessCopyOverhead(inout myHugeStruct: MyStruct) {
        myHugeStruct.increaseMyInt()
    }
    
    var a = MyStruct()
    a = myFunc(a) // copy, copy: overhead
    myFuncWithLessCopyOverhead(&a) // call by reference: no memory reallocation
    

    Also, in the example above---disregarding memory issues---inout can be preferred simply as a good code practice of telling whomever read our code that we are mutating the function caller argument (implicitly shown by the ampersand & preceding the argument in the function call). The following summarises this quite neatly:

    If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

    From Apple Language Guide: Functions - In-Out Parameters.


    For details regarding inout and how it's actually handled in memory (name copy-in-copy-out is somewhat misleading...)---in additional to the links to the language guide above---see the following SO thread:

    • Using inout keyword: is the parameter passed-by-reference or by copy-in copy-out (/call by value result)

    (Edit addition: An additional note)

    The example given in the accepted answer by Lucas Huang above tries to---in the scope of the function using an inout argument---access the variables that were passed as the inout arguments. This is not recommended, and is explicitly warned not to do in the language ref:

    Do not access the value that was passed as an in-out argument, even if the original argument is available in the current scope. When the function returns, your changes to the original are overwritten with the value of the copy. Do not depend on the implementation of the call-by-reference optimization to try to keep the changes from being overwritten.

    Now, the access in this case is "only" non-mutable, e.g. print(...), but all access like this should, by convention, be avoided.

    At request from a commenter, I'll add an example to shine light upon why we shouldn't really do anything with "the value that was passed as an in-out argument".

    struct MyStruct {
        var myStructsIntProperty: Int = 1
    
        mutating func myNotVeryThoughtThroughInoutFunction (inout myInt: Int) {
            myStructsIntProperty += 1
            /* What happens here? 'myInt' inout parameter is passed to this
               function by argument 'myStructsIntProperty' from _this_ instance
               of the MyStruct structure. Hence, we're trying to increase the
               value of the inout argument. Since the swift docs describe inout 
               as a "call by reference" type as well as a "copy-in-copy-out"
               method, this behaviour is somewhat undefined (at least avoidable).
    
               After the function has been called: will the value of
               myStructsIntProperty have been increased by 1 or 2? (answer: 1) */
            myInt += 1
        }
    
        func myInoutFunction (inout myInt: Int) {
            myInt += 1
        }
    }
    
    var a = MyStruct()
    print(a.myStructsIntProperty) // 1
    a.myInoutFunction(&a.myStructsIntProperty)
    print(a.myStructsIntProperty) // 2
    a.myNotVeryThoughtThroughInoutFunction(&a.myStructsIntProperty)
    print(a.myStructsIntProperty) // 3 or 4? prints 3.
    

    So, in this case, the inout behaves as copy-in-copy-out (and not by reference). We summarize by repeating the following statement from the language ref docs:

    Do not depend on the behavioral differences between copy-in copy-out and call by reference.

    0 讨论(0)
  • 2020-12-13 04:00

    inout parameter allow us to change the data of a value type parameter and to keep changes still after the function call has finished.

    0 讨论(0)
  • 2020-12-13 04:08

    inout means that modifying the local variable will also modify the passed-in parameters. Without it, the passed-in parameters will remain the same value. Trying to think of reference type when you are using inout and value type without using it.

    For example:

    import UIKit
    
    var num1: Int = 1
    var char1: Character = "a"
    
    func changeNumber(var num: Int) {
        num = 2
        print(num) // 2
        print(num1) // 1
    }
    changeNumber(num1)
    
    func changeChar(inout char: Character) {
        char = "b"
        print(char) // b
        print(char1) // b
    }
    changeChar(&char1)
    

    A good use case will be swap function that it will modify the passed-in parameters.

    Swift 3+ Note: Starting in Swift 3, the inout keyword must come after the colon and before the type. For example, Swift 3+ now requires func changeChar(char: inout Character).

    0 讨论(0)
  • 2020-12-13 04:09

    when use inout parameter swift 4.0 Work

    class ViewController: UIViewController {
    
        var total:Int = 100
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.paramTotal(total1: &total)
        }
    
        func paramTotal(total1 :inout Int) {
            total1 = 111
            print("Total1 ==> \(total1)")
            print("Total ==> \(total)")
        }
    }
    
    0 讨论(0)
提交回复
热议问题