我知道“&”可以用于位运算,但有时候我看到它在变量名前面。把 &
放在变量名前面是做什么用的?
它作为一个inout
,使变量成为一个in-out参数。In-out实际上意味着通过引用而不是值传递值。这不仅要求按引用接受值,还要按引用传递值,因此请使用 & - foo(&myVar)
而不是foo(myVar)
正如您所看到的,在Swift中,您可以在错误处理中使用它,在这里您必须创建一个错误引用,并使用&
将其传递给函数。如果发生错误,则函数将填充错误值,否则将变量返回为原始值。
为什么要使用它?有时函数已经返回其他值,只返回另一个值(如错误)会令人困惑,因此我们将其作为inout传递。其他时候,我们希望函数来填充这些值,以便我们不必迭代很多返回值,因为函数已经为我们完成了 - 还有其他可能的用途。
return sum & 0xff
是什么意思? - Moosa Baloch&
是按位与运算符。 - Justin Oroz这意味着它是一个输入输出变量。您可以直接对该变量进行操作。它通过地址传递,而不是作为副本。
例如:
var temp = 10
func add(inout a: Int){
a++
}
add(inout:&temp)
temp // 11
10
吗? - mfaani在 Swift 语言中还有另一种未被提及的 & 符号的用法。看下面的例子:
protocol Foo {}
protocol Bar {}
func myMethod(myVar: Foo & Bar) {
// Do something
}
这里的&语法指定了myVar
符合Foo和Bar协议。
作为另一种用例,考虑以下情况:
func myMethod() -> UIViewController & UITableViewDataSource {
// Do something
}
这里我们说的是该方法返回一个符合某个协议(UITableViewDataSource)的类实例(UIViewController)。在Swift 5.1的不透明类型中,这种方式已经有些过时了,但你仍然可能会在早期的Swift 5.1代码中偶尔看到这种语法。
如果在函数中在变量前加上&
,那么这个变量就是一个输入输出变量。
@Icaro已经描述了它的含义,我将举一个例子来说明输入输出变量和输入变量之间的区别:
func majec(inout xValue:Int, var yValue:Int) {
xValue = 100
yValue = 200
}
var xValue = 33
var yValue = 33
majec(&xValue, yValue: yValue)
xValue //100
yValue //33
&
来将值传递给方法或函数调用的inout
参数,这在《Swift编程语言》的函数 > 函数参数标签和参数名 > 引用传递参数中有所记录。但其中还有更多内容。inout
参数和向它们传递值类比于C或C++中的按地址传递或按引用传递。事实上,编译器会将许多inout
参数的使用优化为大致相同的机制(特别是当您调用处理指针的导入的C或ObjC API时)。然而,这些只是优化措施——从语义层面上说,inout
并不会传递地址,这使得编译器可以使此语言结构更加灵活和强大。struct Point {
private var _x: Int
var x: Int {
get {
print("get x: \(_x)")
return _x
}
set {
print("set x: \(newValue)")
_x = newValue
}
}
// ... same for y ...
init(x: Int, y: Int) { self._x = x; self._y = y }
}
func plusOne(num: inout Int) {
num += 1
}
var pt = Point(x: 0, y: 1)
plusOne(num: &pt.x)
// prints:
// get x: 0
// set x: 1
x
是一个计算属性,在使用inout
参数通过“按引用”传递它时,与x
是存储属性或局部变量相同,它的工作方式也与您期望的相同。
swap
函数,它接受任何两个...“事物”并交换它们的值:var a = 1, b = 2
swap(&a, &b)
print(a, b) // -> 2 1
var dict = [ "Malcolm": "Captain", "Kaylee": "Mechanic" ]
swap(&dict["Malcolm"], &dict["Kaylee"])
print(dict) // -> ["Kaylee": "Captain", "Malcolm": "Mechanic"], fanfic ahoy
let window1 = NSWindow()
let window2 = NSWindow()
window1.title = "window 1"
window2.title = "window 2"
var windows = [window1, window2]
swap(&windows[0], &windows[1])
print(windows.map { $0.title }) // -> ["window 2", "window 1"]
inout
的工作方式还可以让您做一些有趣的事情,比如在嵌套调用链上使用+=
运算符:
window.frame.origin.x += 10
...这比分解CGRect
并构造具有不同x
坐标的新矩形要简单得多。
更精细的inout
行为版本被称为“按值结果调用”,以及它可以优化到C风格的“通过地址传递”行为的方式,在The Swift Programming Language的Declarations > Functions > In-Out Parameters一章中有介绍。