Операторы
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_initstruct 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__, здесь всё знакомо.
Всё вместе
Заголовок раздела «Всё вместе»@fieldwise_initstruct 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 пока нет.
Тексты курса — CC BY-NC-SA 4.0, код примеров — Apache 2.0