swift2 何时使用inout参数?

rnmwe5a2  于 2022-11-23  发布在  Swift
关注(0)|答案(8)|浏览(426)

当传递一个类或基元类型到一个函数中时,在函数中对参数所做的任何更改都会反映到类之外。这基本上与inout参数应该做的事情相同。
什么是inout参数的好用例?

aij0ehis

aij0ehis1#

inout表示修改局部变量也会修改传入的参数,如果没有它,传入的参数还是原来的值,尝试在使用inout时考虑引用类型,而不使用值类型。
例如:

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)

swap函数是一个很好的用例,它将修改传入的参数。

    • Swift 3+备注**:Starting in Swift 3inout关键字必须在冒号 * 之后 * 和类型之前。例如,Swift 3+现在需要func changeChar(char: inout Character)
vom3gejh

vom3gejh2#

来自Apple语言参考:说明-输入输出参数:
作为一种优化,当参数是存储在内存中物理地址的值时,在函数体内部和外部都使用相同的内存位置。它满足了复制入复制出模型的所有要求,同时消除了复制的开销。不要依赖于复制入复制出和引用调用之间的行为差异。
如果你有一个函数,它接受一个有点内存方面的大值类型作为参数(比如说,一个大的结构类型),并且返回相同的类型,最后函数返回总是用来替换调用者参数,那么inout是首选的关联函数参数。
考虑下面的例子,这里的注解描述了为什么我们要使用inout而不是常规的类型返回类型函数:

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

同样,在上面的例子中---不考虑内存问题---inout可以作为一个很好的代码实践,告诉任何阅读我们代码的人我们正在改变函数调用者参数(通过函数调用中参数前面的&符号&隐式地显示)。
如果希望函数修改参数值,并且希望这些更改在函数调用结束后保持不变,请将该参数定义为in-out参数。
Apple Language Guide: Functions - In-Out Parameters开始。
有关inout的详细信息以及它在内存中实际是如何处理的(名称copy-in-copy-out有点误导...)---除了上面的语言指南链接之外---请参见下面的SO线程:

上面Lucas Huang给出的例子试图---在使用inout参数的函数作用域中---访问作为inout参数传递的变量。这是不推荐的,并且在ref语言中被明确警告不要这样做:

不要访问作为in-out参数传递得值,即使原始参数在当前作用域中可用.当函数返回时,您对原始参数所做得更改将被副本得值覆盖.不要依赖引用调用优化得实现来防止更改被覆盖.

现在,在这种情况下的访问是“唯一的”不可变的,例如print(...),但是按照惯例,应该避免所有这样的访问。
应一位评论者的要求,我将添加一个例子来阐明为什么我们不应该真正对 “作为in-out参数传递的值” 做任何事情。

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.

因此,在本例中,inout的行为类似于copy-in-copy-out(而不是通过引用)。
不要依赖于复制入复制出和引用调用之间的行为差异。

omhiaaxx

omhiaaxx3#

默认情况下,函数参数是常量。试图在函数体中更改函数参数的值会导致编译时错误。这意味着您不能错误地更改参数的值。如果希望函数修改参数的值,并且希望这些更改在函数调用结束后保持不变,请将该参数定义为in-out参数。

im9ewurl

im9ewurl4#

输入输出参数:修改传递和局部变量值。

func doubleInPlace(number: inout Int) {
     number *= 2
     print(number) 
    
 }

 var myNum = 10 doubleInPlace(number: &myNum)
sigwle7e

sigwle7e5#

inout参数允许我们更改值类型参数的数据,并在函数调用完成后保持更改。

b91juud3

b91juud36#

如果你使用类,那么,正如你所说的,你可以修改类,因为参数是对类的引用。但是当你的参数是值类型时,这就不起作用了(https://docs.swift.org/swift-book/LanguageGuide/Functions.html- In-Out参数部分)
使用inout的一个很好的例子是这个(定义CGPoints的数学):

func + (left: CGPoint, right: CGPoint) -> CGPoint {
  return CGPoint(x: left.x + right.x, y: left.y + right.y)
}

func += (left: inout CGPoint, right: CGPoint) {
  left = left + right
}
6pp0gazn

6pp0gazn7#

基本上,当你想玩变量的地址时,它是有用的,它在数据结构算法中非常有用

bq3bfh9z

bq3bfh9z8#

当使用输入输出参数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)")
    }
}

相关问题