Вывод типов и явная типизация
Урок о том, как Nim угадывает тип значения самостоятельно и когда лучше подсказать тип явно.
Вывод типов (type inference) — способность компилятора самому определить тип переменной по значению, без того, чтобы вы писали этот тип руками.
Зачем это нужно
Nim — язык со строгой статической типизацией: у каждой переменной есть ровно один тип, и он не меняется по ходу программы (в отличие от Python, где переменная может сначала хранить число, а потом строку). Казалось бы, это должно означать, что тип нужно писать каждый раз руками, как в старых версиях Java или C. Но у Nim есть вывод типов: если из значения справа и так понятно, какой тип нужен, компилятор определяет его сам, и вам не приходится об этом думать.
Это удобное сочетание: код читается почти так же коротко, как в Python, но при этом сохраняются все проверки типов, которые ловят ошибки ещё до запуска программы.
Как выглядит вывод типов на практике
Самый простой способ объявить переменную в Nim — вообще не писать тип, а просто присвоить значение:
let city = "Казань"
let population = 1300000
let averageTemp = 5.8
let isCapital = false
echo city, ": ", population, " человек, ", averageTemp, "°C, столица: ", isCapitalВывод:
Казань: 1300000 человек, 5.8°C, столица: falseКомпилятор смотрит на каждое значение справа от = и делает вывод: "Казань" в кавычках — значит, это string; 1300000 без точки — значит, int; 5.8 с точкой — значит, float; false — значит, bool. Это происходит на этапе компиляции, никакой «магии» во время выполнения программы уже не остаётся — тип каждой переменной зафиксирован заранее.
Как указать тип явно
Синтаксис явного указания типа — через двоеточие после имени переменной, перед знаком равенства:
let temperature: float = 5.8
var attempts: int = 0
let greeting: string = "Привет!"Смысл тот же, что и без явного типа, но теперь тип виден сразу в объявлении, а не только выводится из значения. Более того, тип и значение можно комбинировать так, чтобы результат отличался от того, что вывелся бы сам по себе:
let score: float = 10
echo scoreВывод:
10.0Здесь литерал 10 сам по себе выглядит как целое число, но явное указание : float говорит компилятору: «сохрани его как дробное». Nim в этом случае аккуратно преобразует целочисленный литерал в дробный прямо при компиляции.
Когда тип обязательно нужен явно
Бывают ситуации, где Nim не может сам угадать тип, потому что по правой части выражения это неоднозначно. Самый частый пример — когда сначала объявляют переменную, а значение присваивают только позже:
var balance: int
balance = 100
echo "Баланс: ", balanceВывод:
Баланс: 100Без начального значения компилятору неоткуда взять подсказку о типе — поэтому здесь тип после двоеточия обязателен. Если его не указать, компилятор Nim выдаст ошибку прямо на этапе сборки:
var balance
balance = 100 # ошибка: тип не определёнВывод:
Error: type of 'balance' is not knownЯвный тип как средство читаемости
Даже когда вывод типов справился бы и сам, иногда явный тип стоит писать нарочно — не для компилятора, а для человека, который потом будет читать код. Например, в объявлении функции тип параметра всегда обязателен — по одному лишь имени параметра компилятору неоткуда узнать тип:
proc describeAge(age: int): string =
"Возраст: " & $age & " лет"
echo describeAge(15)Вывод:
Возраст: 15 летЗдесь age: int — обязательная часть объявления функции (proc), а не подсказка компилятору «для галочки»: без типа параметра компилятор просто не соберёт код, ведь он должен заранее знать, какие операции с этим параметром допустимы.
Частые ошибки
- Думать, что раз тип не написан явно, значит, его вообще нет. Это не так: тип определяется всегда, просто иногда его пишете вы, а иногда — выводит компилятор. С точки зрения строгости проверок разницы нет.
- Объявлять переменную без значения и без типа.
var xбез начального значения и без: типкомпилятор не пропустит — неоткуда взять подсказку. - Ожидать, что тип может «сам поменяться» по ходу программы. В отличие от Python, если
let x = 5вывелось какint, эта переменная уже никогда не сможет хранить строку или список — тип фиксируется один раз, при объявлении.
Итоги
- Nim умеет выводить тип переменной по значению справа от
=— писать тип руками не обязательно. - Явный тип указывается через двоеточие:
let x: float = 10. - Явный тип обязателен, когда значение не присваивается сразу при объявлении, а также в параметрах функций.
- Какой бы способ вы ни выбрали, тип переменной фиксируется на этапе компиляции и не меняется дальше.