Изменяемость аргументов и владение
Mojo поддерживает полноценную семантику и обеспечивает безопасность памяти с помощью надежной модели владения значениями (аналогично средству проверки заимствований в Rust). Итак, ниже приводится краткое введение в то, как вы можете обмениваться ссылками на значения через аргументы функции.
Обратите внимание: вышеприведенный метод add() не изменяет x или y, а только считывает значения. Фактически, как написано, функция не может их изменять, поскольку аргументы fn по умолчанию являются неизменяемыми ссылками.
С точки зрения соглашений об аргументах это называется «заимствованием», и хотя это значение по умолчанию для функций fn, вы можете сделать это явным образом с помощью заимствованного объявления, например (это ведет себя точно так же, как и функция add() выше):
Код: Выделить всё
fn add(borrowed x: Int, borrowed y: Int) -> Int:
return x + y
Если вы хотите, чтобы аргументы были изменяемыми, вам необходимо объявить соглашение об аргументах inout. Это означает, что изменения, внесенные в аргументы внутри функции, видны за ее пределами.
Например, эта функция может изменять исходные переменные:
Код: Выделить всё
fn add_inout(inout x: Int, inout y: Int) -> Int:
x += 1
y += 1
return x + y
var a = 1
var b = 2
c = add_inout(a, b)
print(a)
print(b)
print(c)
2
3
5
Другой вариант — объявить аргумент как принадлежащий, что обеспечивает функции полное владение значением (оно изменяемо и гарантированно уникально). Таким образом, функция может изменять значение и не беспокоиться о влиянии на переменные вне функции. Например:
Код: Выделить всё
fn set_fire(owned text: String) -> String:
text += "🔥"
return text
fn mojo():
let a: String = "mojo"
let b = set_fire(a)
print(a)
print(b)
mojo()
mojo
mojo🔥
В этом случае Mojo создает копию a и передает ее в качестве текстового аргумента. Оригинальная строка все еще жива и здорова.
Однако, если вы хотите передать функцию право собственности на значение и не хотите делать копию (что может быть дорогостоящей операцией для некоторых типов), вы можете добавить оператор «передачи» ^ при передаче функции. . Оператор передачи эффективно уничтожает имя локальной переменной — любая попытка вызвать его позже приведет к ошибке компилятора.
Попробуйте сделать это выше, изменив вызов set_fire() так:
Теперь вы получите сообщение об ошибке, поскольку оператор передачи фактически уничтожает переменную a, поэтому, когда следующая функция print() пытается использовать a, эта переменная больше не инициализируется.
Если вы удалите print(a), то все будет работать нормально.
Эти соглашения об аргументах предназначены для того, чтобы предоставить системным программистам полный контроль над оптимизацией памяти, обеспечивая при этом безопасный доступ и своевременное освобождение памяти — компилятор Mojo гарантирует, что никакие две переменные не имеют изменяемого доступа к одному и тому же значению одновременно, а время жизни каждого значения невелико. четко определены, чтобы строго предотвратить любые ошибки памяти, такие как «использование после освобождения» и «двойное освобождение».
Примечание. В настоящее время Mojo всегда создает копию, когда функция возвращает значение.