I know about the ampersand as a bit operation but sometimes I see it in front of variable names. What does putting an &
in front of variables do?
It works as an inout
to make the variable an in-out parameter. In-out means in fact passing value by reference, not by value. And it requires not only to accept value by reference, by also to pass it by reference, so pass it with & - foo(&myVar)
instead of just foo(myVar)
As you see you can use that in error handing in Swift where you have to create an error reference and pass it to the function using &
the function will populate the error value if an error occur or pass the variable back as it was before
Why do we use it? Sometimes a function already returns other values and just returning another one (like an error) would be confusing, so we pass it as an inout. Other times we want the values to be populated by the function so we don't have to iterate over lots of return values, since the function already did it for us - among other possible uses.
return sum & 0xff
–
Lynnlynna &
is a bitwise AND operator –
Exclamation There's another function of the ampersand in the Swift language that hasn't been mentioned yet. Take the following example:
protocol Foo {}
protocol Bar {}
func myMethod(myVar: Foo & Bar) {
// Do something
}
Here the ampersand syntax is stating that myVar
conforms to both the Foo and Bar protocol.
As another use case, consider the following:
func myMethod() -> UIViewController & UITableViewDataSource {
// Do something
}
Here we're saying that the method returns a class instance (of UIViewController) that conforms to a certain protocol (UITableViewDataSource). This is rendered somewhat obsolete with Swift 5.1's Opaque Types but you may see this syntax in pre-Swift 5.1 code from time to time.
It means that it is an in-out variable. You can do something directly with that variable. It is passed by address, not as a copy.
For example:
var temp = 10
func add(inout a: Int){
a++
}
add(inout:&temp)
temp // 11
10
? –
Kwiatkowski If you put &
before a variable in a function, that means this variable is inout variable.
@Icaro already described what it means, I will just give an example to illustrate the difference between inout variables and in variables:
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
As noted in other answers, you use prefix &
to pass a value to an inout
parameter of a method or function call, as documented under Functions > Function Argument Labels and Parameter Names > In-Out Parameters in The Swift Programming Language. But there's more to it than that.
You can, in practice, think about Swift inout
parameters and passing values to them as being similar to C or C++ pass-by-address or pass-by-reference. In fact, the compiler will optimize many uses of inout
parameters down to roughly the same mechanics (especially when you're calling imported C or ObjC APIs that deal in pointers). However, those are just optimizations — at a semantic level, inout
really doesn't pass addresses around, which frees the compiler to make this language construct more flexible and powerful.
For example, here's a struct that uses a common strategy for validating access to one of its properties:
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 }
}
(In "real" code, the getter and setter for x
could do things like enforcing minimum/maximum values. Or x
could do other computed-property tricks, like talking to a SQL database under the hood. Here we just instrument the call and get/set the underlying private property.)
Now, what happens when we pass x
to an inout
parameter?
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
So, even though x
is a computed property, passing it "by reference" using an inout
parameter works the same as you'd expect it to if x
were a stored property or a local variable.
This means that you can pass all sorts of things "by reference" that you couldn't even consider in C/C++/ObjC. For example, consider the standard library swap
function, that takes any two... "things" and switches their values:
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"]
The the way inout
works also lets you do fun stuff like using the +=
operator on nested call chains:
window.frame.origin.x += 10
... which is a whole lot simpler than decomposing a CGRect
just to construct a new one with a different x
coordinate.
This more nuanced version of the inout
behavior, called "call by value result", and the ways it can optimize down to C-style "pass by address" behavior, is covered under Declarations > Functions > In-Out Parameters in The Swift Programming Language.
inout
is it makes me want to head down the street for a double-double and a milkshake. –
Sextuple © 2022 - 2024 — McMap. All rights reserved.