Skip to content

Система типов

This content is not available in your language yet.

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

Без единого импорта:

ТипЧто этоПример
IntЦелое размером в машинное слово, на 64-битной системе — 64 битаvar n = 42
Float64Число с плавающей точкой двойной точностиvar x = 1.5
BoolЛогическое значениеvar flag = True
StringСтрока в UTF-8var s = "Привет"
SIMDВектор из нескольких чисел одного типаSIMD[DType.float32, 4](1, 2, 3, 4)
TupleКортеж, элементы могут быть разных типовvar t = (1, "два", 3.0)
ListСписок значений одного типаvar xs: List[Int] = [1, 2, 3]
DictСловарьvar d = Dict[String, Int]()
InlineArrayМассив фиксированной длины, живёт на стекеInlineArray[Int, 3](fill=0)

Из стандартной библиотеки импортируются, например:

from std.collections.set import Set
from std.collections.optional import Optional

Звучит странно, но это два разных типа, и один в другой сам не превратится:

var x = 3 # Int
var y: Int64 = x # ошибка компиляции
var z = Int64(x) # так правильно
error: cannot implicitly convert 'Int' value to 'Int64'
Что это значит

Int — это «целое машинного размера», зависящее от платформы. Int64 — это «ровно 64 бита», размер фиксирован. Смысл разный, поэтому автоматического преобразования нет.

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

Преобразуйте явно: Int64(x). Правило простое: Int — для обычной арифметики и индексов, размерные типы (Int8, UInt8, Int32, Int64, Float32…) — когда важен точный формат данных: работа с файлами, сетью, GPU или экономия памяти.

var small: Int8 = 127
small += 1
print(small) # -128

Ошибки не будет: тип занимает один байт, 127 — его максимум, дальше счётчик заворачивается. В Python целые растут неограниченно, здесь — нет. Если значение может выйти за границы, берите тип пошире или проверяйте сами.

Самое коварное место главы. Посмотрите внимательно:

def main():
print(7 / 2) # 3.5
var a = 7
var b = 2
print(a / b) # 3
Результат

3.5 3

Разница в том, что делится. В первой строке — литералы: компилятор вычисляет их сам ещё на этапе сборки и получает дробное число. Во второй — переменные типа Int, а деление двух Int даёт Int, дробная часть отбрасывается.

Питониста это подловит обязательно: в Python / всегда даёт float.

print(Float64(a) / Float64(b)) # 3.5 — то, что вы ожидали
print(a // b) # 3 — честное целочисленное деление

Правило на каждый день: нужна дробь — приводите к Float64 явно.

SIMD расшифровывается как single instruction, multiple data: одна инструкция процессора обрабатывает сразу несколько чисел. Именно ради этого Mojo и требует современный процессор.

def main():
var vector = SIMD[DType.float32, 4](1, 2, 3, 4)
print(vector * 2)
print(vector.reduce_add())
Результат

[2.0, 4.0, 6.0, 8.0] 10.0

В квадратных скобках указываются параметры — тип элемента и количество элементов. Оба должны быть известны на этапе компиляции, потому что от них зависит, какую машинную инструкцию сгенерировать.

Подробно — в главе SIMD с нуля.

Int(3.9) # 3, дробная часть отбрасывается
Float64(7) # 7.0
String(255) # "255"
Int(String("42")) # 42, но может бросить исключение

Последняя строка требует raises у вызывающей функции: строка может оказаться не числом, и это честно отражено в типе операции.

🐍 Python
total = 0
total += 1.5 # молча станет float
🔥 Mojo
var total = 0
total += Int(1.5) # решение принимаете вы

Python сам меняет тип переменной по ходу дела. В Mojo так нельзя: сначала объявили тип, дальше все преобразования пишете руками.

numbers.mojo
def main() raises:
# Int — целое машинное слово, на 64-битной системе это 64 бита
var big = 2**62
print("большое целое:", big)
# Размерные типы указываются явно и НЕ смешиваются с Int автоматически
var small: Int8 = 127
small += 1
print("Int8 после переполнения:", small)
# Деление: осторожно
var a = 7
var b = 2
print("Int / Int:", a / b)
print("после преобразования:", Float64(a) / Float64(b))
print("целочисленное деление:", a // b)
# SIMD — обычный тип языка, операции идут сразу над всеми элементами
var vector = SIMD[DType.float32, 4](1, 2, 3, 4)
print("вектор * 2:", vector * 2)
print("сумма элементов:", vector.reduce_add())
# Преобразования всегда явные
var text = String(255)
var back = Int(text)
print("строка и обратно:", text, back + 1)
Результат

большое целое: 4611686018427387904 Int8 после переполнения: -128 Int / Int: 3 после преобразования: 3.5 целочисленное деление: 3 вектор * 2: [2.0, 4.0, 6.0, 8.0] сумма элементов: 10.0 строка и обратно: 255 256

var numbers: List[Int] = [1, 2, 3]
var ages = Dict[String, Int]()
var buffer = InlineArray[Int, 3](fill=0)

Все они обобщённые (generic): тип элементов указывается в квадратных скобках и известен компилятору. Список List[Int] хранит числа подряд в памяти — без обёрток, заголовков и указателей, как это устроено в Python. Отсюда и скорость, и требование однородности.

InlineArray отличается от List тем, что его длина известна на этапе компиляции, и он не выделяет память в куче — живёт прямо на стеке. Для маленьких буферов фиксированного размера это заметно быстрее.

Важная особенность языка: Int, String, List не встроены в компилятор на особых правах. Они написаны на самом Mojo, в стандартной библиотеке, теми же средствами, что доступны вам. Свой числовой тип с перегруженными операторами будет ровно таким же гражданином языка, как Int.

Это не философия, а практическое следствие: язык можно расширять, не дожидаясь новых версий компилятора.

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

Почему `7 / 2` даёт 3.5, а `a / b` для двух Int — 3?

В первом случае делятся литералы: компилятор вычисляет выражение на этапе сборки и получает дробное число. Во втором делятся значения типа Int, а деление Int на Int даёт Int с отброшенной дробной частью. Нужна дробь — приводите к Float64 явно.

Чем `Int` отличается от `Int64`?

Int — целое размером в машинное слово (на 64-битных системах это 64 бита), Int64 — ровно 64 бита независимо от платформы. Это разные типы, и неявного преобразования между ними нет. Int — для обычной арифметики и индексов, размерные типы — когда важен точный формат данных.

Что напечатает `var x: Int8 = 127` с последующим `x += 1`?

-128. Однобайтовый тип переполняется без всякой ошибки: 127 — его максимум, дальше значение заворачивается. В Python целые растут неограниченно, в Mojo — нет.

Строки заслуживают отдельного разговора — особенно когда в них кириллица: Строки и Unicode.

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

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