Всем привет! В данной статье я постараюсь рассказать, что такое generic процедуры и converter’ы в Nim (и показать примеры их использования)
Что такое Nim? Nim – компилируемый (в C, C++, Objective C и JS) высокоуровневый язык программирования со сборщиком мусора, имеющий три основных цели (в порядке приоритета): производительность, выразительность, элегантность. Официальный сайт языка, репозиторий на GitHub.
Также в Nim достаточно развито метапрограммирование (дженерики, шаблоны, макросы).
Для начала я покажу, как выглядит процедура, которая имеет один аргумент типа int, и возвращает тоже int:
proc plusOne(arg: int): int =
return arg + 1
echo plusOne(5) # Выведет 6
Как я думаю, тут всё предельно ясно (прибавляем число 1 к аргументу arg типа int и возвращаем результат)
Дженерики в Nim — это процедуры, которые могут принимать несколько типов (компилятор сделает отдельную версию процедуры для каждого типа, который использовался с данной процедурой).
1 пример — обычный дженерик
Этот пример выводит длину объекта, если для данного объекта имеется процедура len (почти что полный аналог __len__ в Python):
proc tryLen[T](something: T) =
when compiles(something.len): # something.len это тоже самое, что len(something)
echo something.len
else:
echo "У этого типа не объявлена процедура `len`"
# Объявим тип нового объекта, у которого не будет процедуры `len` (так как мы её не объявляли)
type MyObject = object
# Создадим сам объект
let myObj = MyObject()
tryLen([1, 2, 3]) # Выведет 3
tryLen("Hello world!") # Выведет 12
tryLen(myObj) # Выведет "У этого типа не объявлена процедура `len`"
Этот пример намного сложнее предыдущего, я постараюсь кратко объяснить, что тут происходит:
Для начала мы объявляем саму процедуру tryLen, которая принимает аргумент something типа T (T — это чаще всего используемое название для неопределённого типа, вместо T можно написать abcd, и всё будет работать точно так же).
Затем мы используем специальное условие when compiles (это аналог if, но условие должно быть известно во время компиляции, и сам when в скомпилированный код не попадает). Если это условие выполняется для данного типа — выводим результат процедуры len для данного аргумента, если не выполняется — выводим сообщение.
Затем мы создаём объект типа MyObject, и применяем tryLen к массиву [1, 2, 3], строке «Hello world!», и нашему объекту.
2 пример — конвертер
Он служит для неявного конвертирования одного типа в другой (но он не особо приветствуется самими разработчиками языка, так как в этом случае всё-таки «явное лучше неявного»).
В данном примере мы сделаем конвертер, который конвертирует наш тип объекта MyObject в число (в данном случае — просто 1):
type MyObject = object
let myObj = MyObject()
# Если процедура или конвертер маленькие, то можно сразу написать возвращаемое значение без return
# Имя конвертера не играет какой-либо особенной роли
converter toInt(b: MyObject): int = 1
# Конвертер можно вызвать явно (однако в этом случае лучше сделать обычную процедуру)
echo myObj.toInt + 1 # Выведет 2
# Или он сам может вызываться неявно:
echo myObj + 1 # Тоже выведет 2, так как toInt неявно конвертировал myObj в число 1
Использование конвертеров — спорная тема (в стандартной библиотеке языка они почти не используются), но я отношусь к ним нейтрально.
Последний пример — дженерик конвертер
Да, звучит страшно, но на самом деле всё не так сложно. С помощью него мы сможем сделать Nim чуть более похожим на Python (а именно — неявно преобразовывать некоторые типы к bool)
converter toBool[T](arg: T): bool =
# Если для данного типа аргумента имеется процедура len
when compiles(arg.len):
arg.len > 0
# Если аргумент можно сложить с числом того же типа T
# T(0) используется для того, чтобы условие одновременно совпадало
# со всеми числовыми типами (т.е мы конвертируем 0 в данный тип)
elif compiles(arg + T(0)):
arg > 0
if [1, 2, 3]: # Длина массива
echo "True!"
if @[1, 2, 3]: # Длина последовательности
echo "True too!"
if "": # Пустая строка
echo "No :("
if 5: # Integer
echo "Nice number!"
if 0.0001: # Float
echo "Floats are nice too!"
Спасибо за чтение! Я надеюсь, что вы смогли почерпнуть для себя что-то новое.
Автор: Tiberiumk