Я знаю об амперсанде как о бит операции, но иногда вижу его перед именами переменных. Что делает &
перед переменными?
Что означает амперсанд (&) на языке Swift?
Ответ 1
Он работает как inout
, чтобы сделать переменную параметром in-out. In-out означает фактически передачу значения по ссылке, а не по значению. И это требует не только для принятия значения по ссылке, так и для передачи его по ссылке, поэтому передайте его с и - foo(&myVar)
вместо foo(myVar)
Как вы видите, вы можете использовать это при передаче ошибок в Swift, где вам нужно создать ссылку на ошибку и передать ее функции, используя &
, функция заполнит значение ошибки, если возникнет ошибка или передайте переменную обратно как это было до
Почему мы его используем? Иногда функция уже возвращает другие значения и просто возвращает другую (например, ошибку), будет путать, поэтому мы передаем ее как inout. В других случаях мы хотим, чтобы значения были заполнены функцией, поэтому нам не нужно перебирать множество возвращаемых значений, так как функция уже сделала это для нас - среди других возможных применений.
Я надеюсь, что это поможет!
Ответ 2
Это означает, что это переменная in-out. Вы можете сделать что-то прямо с этой переменной. Он передается по адресу, а не как копия.
Например:
var temp = 10
func add(inout a: Int){
a++
}
add(&temp)
temp // 11
Ответ 3
Если вы поместите &
перед переменной в функцию, это означает, что эта переменная не имеет переменной.
@Икаро уже описал, что это значит, я просто приведу пример, чтобы проиллюстрировать разницу между inout-переменными и переменными:
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
Ответ 4
Как указано в других ответах, вы используете префикс &
для передачи значения в параметр inout
метода или вызова функции, как описано в Функции > Ярлыки аргументов функции и имена параметров > Параметры вывода на языке Swift Programming. Но там больше, чем это.
На практике вы можете думать о параметрах Swift inout
и передавать им значения как похожие на C или С++ pass-by-address или pass-by-reference - и когда вы вызываете импортированные 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 }
}
(В "реальном" коде геттер и сеттер для x
могут делать такие вещи, как принудительное использование минимальных/максимальных значений. Или x
может выполнять другие трюки с вычисленными свойствами, например, разговаривать с базой данных SQL под капотом. Здесь мы просто обрабатываем вызов и получаем/устанавливаем базовое частное свойство.)
Теперь, что происходит, когда мы передаем x
в параметр inout
?
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
является сохраненным свойством или локальной переменной.
Это означает, что вы можете передавать всевозможные вещи "по ссылке", которые вы даже не могли рассмотреть в C/С++/ObjC. Например, рассмотрим стандартную библиотечную функцию 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
, называемая "результат по результату", и способы ее оптимизации до поведения "pass by address" в стиле C, рассматриваются в Объявления > Функции > Параметры вывода на языке Swift Programming.