Перейти к содержимому

Переменные

В Python переменная — это имя, привязанное к объекту, и её можно в любой момент перепривязать к чему угодно. В Mojo переменная — это участок памяти известного размера с известным типом. Отсюда все отличия ниже.

Переменная объявляется словом var при первом присваивании:

var count: Int = 0 # с явным типом
var total = 0.0 # тип выведен из значения — здесь Float64
var name = "Аня" # String

Дальше var не нужен — это уже не объявление, а изменение значения:

count = 5
count += 1

Тип переменной определяется в момент объявления и больше не меняется:

🐍 Python
x = 1
x = "теперь строка" # нормально
🔥 Mojo
var x = 1
x = "теперь строка" # ошибка компиляции

В Python имя просто перевешивается на другой объект. В Mojo под x отведено восемь байт под целое число — строка туда не поместится ни физически, ни по смыслу.

error: cannot implicitly convert 'StringLiteral[...]' value to 'Int'
Что это значит

Вы присваиваете переменной значение другого типа.

Как исправить

Либо заведите новую переменную с другим именем, либо преобразуйте значение явно: var text = String(x).

Так можно — но пользоваться значением до присваивания компилятор не даст:

var limit: Int # объявлена, но пуста
limit = 100 # теперь в ней есть значение
error: use of uninitialized value 'x'
Что это значит

Переменная объявлена, но значение в неё ещё не положили — а вы уже пытаетесь его прочитать.

Как исправить

Присвойте значение до первого использования. Компилятор отслеживает все ветви кода: если хотя бы по одной из них переменная остаётся пустой, будет ошибка.

Это важнее, чем кажется. В Python неинициализированная переменная — это NameError во время выполнения, у пользователя. В Mojo такой код просто не соберётся.

Главное отличие от Python. Переменная живёт до конца блока, в котором объявлена, а не до конца функции:

🐍 Python
if True:
message = "привет"
print(message) # работает
🔥 Mojo
if True:
var message = "привет"
print(message) # ошибка: имя неизвестно

Блок — это тело if, while, for, with и любой другой конструкции с отступом. Как в C++, Rust или Java.

error: use of unknown declaration 'message'
Что это значит

Имя не существует в этой точке программы: либо опечатка, либо переменная объявлена во вложенном блоке и уже «умерла».

Как исправить

Объявите переменную до блока, если она нужна и после него.

Внутри вложенного блока имя можно затенить (shadow) — это будет отдельная переменная, а внешняя останется нетронутой.

scope.mojo
def main():
var counter = 0
# Переменная, объявленная внутри блока, живёт только в этом блоке
if counter == 0:
var message = "счётчик пуст"
print(message)
# Здесь `message` уже не существует — попытка обратиться к нему
# не скомпилируется
# Имя можно затенить во вложенном блоке: это разные переменные
var name = "внешняя"
while counter < 1:
var name = "внутренняя"
print("внутри блока:", name)
counter += 1
print("снаружи блока:", name)
# Объявить сейчас, значение присвоить позже — можно
var limit: Int
if counter > 0:
limit = 100
else:
limit = 0
print("предел:", limit)
Результат

счётчик пуст внутри блока: внутренняя снаружи блока: внешняя предел: 100

В ранних версиях Mojo была пара let и var — для неизменяемых и изменяемых переменных. В 1.0 let удалён: любую переменную можно изменить.

Означает ли это, что от неизменяемости отказались? Нет — её перенесли туда, где она действительно нужна: в передачу аргументов. Функция получает значение только для чтения, если явно не сказано иначе. Подробно — в главе Конвенции передачи аргументов.

Если значение известно заранее и меняться не должно, объявите его через comptime — компилятор вычислит его на этапе сборки и подставит в код:

comptime MAX_USERS = 100
def main():
comptime BUFFER = 4096
print(MAX_USERS, BUFFER)
Результат

100 4096

Такие значения можно использовать там, где обычная переменная не подойдёт — например, задавать размер массива или ширину SIMD-вектора. Об этом целый раздел Метапрограммирование.

Правила как в Python: буквы, цифры, подчёркивания, начинать с цифры нельзя. Кириллица в именах технически возможна, но не используйте её — код читают и правят разные люди, а раскладку переключать неудобно.

Принятый стиль в Mojo совпадает с питоновским: snake_case для переменных и функций, CamelCase для типов, UPPER_CASE для констант.

🎯 Проверь себя

Почему `var message` внутри `if` не виден после блока?

В Mojo область видимости переменной ограничена блоком, где она объявлена. Это позволяет компилятору точно знать, когда значение больше не нужно, и вовремя освободить память. В Python область видимости — вся функция.

Можно ли объявить переменную без значения?

Да: var limit: Int. Но прочитать её до первого присваивания нельзя — компилятор проверяет все ветви кода и выдаст ошибку use of uninitialized value.

Куда делось ключевое слово `let` из старых примеров?

Удалено в Mojo 1.0. Все переменные изменяемы, а неизменяемость выражается конвенцией передачи аргументов: функция по умолчанию получает значение только для чтения.

Мы всё время говорили «тип выведен из значения». Пора разобраться, какие вообще бывают типы и почему Int — это не то же самое, что Int64.

Примеры проверены на Mojo 1.0.0

Тексты курса — CC BY-NC-SA 4.0, код примеров — Apache 2.0