Skip to content

Операторы

This content is not available in your language yet.

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

def main():
print(2 + 3 * 4) # приоритет как в математике
print((2 + 3) * 4)
print(2**10) # степень
print(7 % 3) # остаток
print(7 // 2) # целочисленное деление
Результат

14 20 1024 1 3

Составные присваивания +=, -=, *=, /=, //=, %=, **= работают как обычно. Операторов ++ и -- нет — как и в Python.

def main():
var age = 25
print(age == 25, age != 30, age > 18)
print(18 <= age < 65) # цепочка сравнений
Результат

True True True True

Цепочки сравнений — приятное наследие Python: 18 <= age < 65 читается как в математике и вычисляется один раз, без повторного обращения к age.

Строки сравниваются посимвольно, по кодовым точкам:

def main():
print(String("а") < String("б"))
print(String("абв") == String("абв"))
Результат

True True

def main():
print(True and False, True or False, not True)
Результат

False True False

Как и в Python, and и or вычисляются лениво: если результат уже ясен по левому операнду, правый не вычисляется. Это позволяет писать привычное if index < len(items) and items[index] > 0.

def main():
print(5 & 3, 5 | 3, 5 ^ 3) # и, или, исключающее или
print(1 << 4, 16 >> 2) # сдвиги
Результат

1 7 6 16 4

В Python побитовые операции — экзотика. В Mojo, где вы работаете с конкретными размерными типами, флагами и данными, они встречаются заметно чаще.

Обе конструкции перенесены из Python без изменений:

def main():
var temperature = 25
print("тепло" if temperature > 20 else "прохладно")
var count: Int
if (count := temperature // 10) > 1:
print("десятков:", count)
Результат

тепло десятков: 2

Оператор := присваивает и сразу возвращает значение — удобно, когда результат нужен и в условии, и в теле.

Вот здесь Mojo интереснее Python. Чтобы структура умела складываться, достаточно определить метод __add__:

@fieldwise_init
struct Money(ImplicitlyCopyable):
var amount: Int
def __add__(self, other: Money) -> Money:
return Money(self.amount + other.amount)
def main():
var total = Money(100) + Money(250)
print(total.amount)
Результат

350

Никакой динамической диспетчеризации при этом не происходит: компилятор подставляет вызов напрямую, и Money(100) + Money(250) стоит ровно столько же, сколько сложение двух чисел.

ОператорМетод
a + b__add__
a - b__sub__
a * b__mul__
a / b__truediv__
a // b__floordiv__
a % b__mod__
a ** b__pow__
a == b__eq__
a != b__ne__
a < b__lt__
a <= b__le__
a > b__gt__
a >= b__ge__
a[i]__getitem__
len(a)__len__
x in a__contains__

Имена совпадают с питоновскими — если вы когда-нибудь писали классы с __eq__, здесь всё знакомо.

vector.mojo
@fieldwise_init
struct Vec2(ImplicitlyCopyable):
"""Двумерный вектор с перегруженными операторами."""
var x: Float64
var y: Float64
def __add__(self, other: Vec2) -> Vec2:
return Vec2(self.x + other.x, self.y + other.y)
def __sub__(self, other: Vec2) -> Vec2:
return Vec2(self.x - other.x, self.y - other.y)
def __mul__(self, factor: Float64) -> Vec2:
return Vec2(self.x * factor, self.y * factor)
def __eq__(self, other: Vec2) -> Bool:
return self.x == other.x and self.y == other.y
def show(self, label: String):
print(label, "(" + String(self.x) + ", " + String(self.y) + ")")
def main():
var a = Vec2(1.0, 2.0)
var b = Vec2(3.0, 4.0)
(a + b).show("сумма:")
(b - a).show("разность:")
(a * 3.0).show("умножение на число:")
print("равны ли a и a:", a == Vec2(1.0, 2.0))
# Обычная арифметика и приоритет операций — как в Python
print("2 + 3 * 4 =", 2 + 3 * 4)
print("(2 + 3) * 4 =", (2 + 3) * 4)
print("2 в степени 10:", 2**10)
print("остаток 7 % 3:", 7 % 3)
# Побитовые операции
print("5 & 3 =", 5 & 3, " 5 | 3 =", 5 | 3, " 5 ^ 3 =", 5 ^ 3)
print("сдвиги:", 1 << 4, 16 >> 2)
# Сравнения можно объединять в цепочку
var age = 25
print("18 <= age < 65:", 18 <= age < 65)
Результат

сумма: (4.0, 6.0) разность: (2.0, 2.0) умножение на число: (3.0, 6.0) равны ли a и a: True 2 + 3 * 4 = 14 (2 + 3) * 4 = 20 2 в степени 10: 1024 остаток 7 % 3: 1 5 & 3 = 1 5 | 3 = 7 5 ^ 3 = 6 сдвиги: 16 4 18 <= age < 65: True

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

Что нужно добавить в структуру, чтобы работал оператор `==`?

Метод __eq__(self, other: ...) -> Bool. Имена методов совпадают с питоновскими, так что если вы писали классы с __eq__ в Python — здесь ровно то же самое.

Почему сравнение строк не годится для сортировки по алфавиту?

Оно идёт по номерам символов в Unicode: заглавные буквы оказываются «меньше» строчных, а «ё» стоит далеко от «е». Для человеческого порядка нужна нормализация или своя функция сравнения.

Стоит ли перегрузка оператора дороже обычного вызова функции?

Нет. Вызов подставляется компилятором напрямую, динамического поиска метода во время выполнения не происходит — в отличие от Python.

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

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

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