Поделиться страницей

Изучите X за Y минут

Где X=Nim

Nim (ранее известный, как Nimrod) — язык программирования со статической типизацией, поддерживающий процедурный, объектно-ориентированный, функциональный и обобщённый стили программирования.

Nim эффективный, выразительный и элегантный.

var                    # Объявление (и присваивание) переменных,
  буква: char = 'n'    # с указанием типа или без
  язык = "N" & "im"
  nLength : int = len(язык)
  boat: float
  правда: bool = false

let              # Используйте let *сразу* для объявления и связывания переменных.
  ноги = 400     # ноги неизменяемый.
  руки = 2_000   # Символ _ игнорируется и удобен для длинных чисел.
  почтиПи = 3.15

const            # Константы вычисляются во время компиляции. Это обеспечивает
  debug = true   # производительность и полезно в выражениях этапа компиляции.
  компилироватьПлохойКод = false

when компилироватьПлохойКод:    # `when` это `if` этапа компиляции.
  ноги = ноги + 1               # Эта ошибка никогда не будет скомпилирована.
  const ввод = readline(stdin)  # Значения констант должны быть известны во
                                # время компиляции.

discard 1 > 2 # Примечание. Компилятор будет жаловаться, если результат
              # выражения не используется. `discard` обходит это.

discard """
Это может использоваться как многострочный комментарий.
Или для не поддающегося синтаксическому анализу, сломанного кода
"""

#
# Структуры данных
#

# Кортежи

var
  дитя: tuple[имя: string, возраст: int]             # Кортежи определяют *как* имя поля
  сегодня: tuple[солнце: string, температура: float] # так *и* порядок полей.

дитя = (имя: "Rudiger", возраст: 2) # Присвоить все сразу литералом ()
сегодня.солнце = "Пасмурно"         # или отдельно по полям.
сегодня.температура = 20.1

# Последовательности

var
  напитки: seq[string]

напитки = @["Вода", "Сок", "Какао"] # @[V1,..,Vn] является литералом
                                    # последовательности

напитки.add("Молоко")

if "Молоко" in напитки:
  echo "У нас тут Молоко и ещё", напитки.len - 1, " напиток(ов)"

let мойНапиток = напитки[2]

#
# Определение типов
#

# Определение собственных типов позволяет компилятору работать на вас.
# Это то, что делает статическую типизацию мощной и полезной.

type
  Имя = string      # Псевдоним типа дает вам новый тип, который равнозначен
  Возраст = int     # старому типу, но более нагляден.
  Человек = tuple[имя: Имя, возраст: Возраст] # Определение структур данных.
  АльтернативныйСинтаксис = tuple
    fieldOne: string
    secondField: int

var
  джон: Человек = (имя: "John B.", возраст: 17)
  новыйВозраст: int = 18 # Было бы лучше использовать Возраст, чем int

джон.возраст = новыйВозраст # Но это все же работает, потому что int и Возраст синонимы.

type
  Нал = distinct int          # `distinct` делает новый тип несовместимым с его
  Описание = distinct string  # базовым типом.

var
  money: Нал = 100.Нал   # `.Нал` преобразует int в наш тип
  описание: Описание  = "Interesting".Описание

when компилироватьПлохойКод:
  джон.возраст  = money       # Error! возраст is of type int and money is Нал
  джон.имя = описание         # Компилятор говорит: "Нельзя!"

#
# Дополнительные типы и структуры данных
#

# Перечисления позволяют типу иметь одно из ограниченного числа значений

type
  Цвет = enum цКрасный, цГолубой, цЗеленый
  Направление = enum  # Альтернативный формат
    нСевер
    нЗапад
    нВосток
    нЮг
var
  напр = нСевер     # `напр` имеет тип Направление, со значением `нСевер`
  точка = цЗеленый  # `точка` имеет тип Цвет, со значением `цЗеленый`

discard нСевер > нВосток  # Перечисления обычно являются "порядковыми" типами

# Поддиапазоны определяют ограниченный допустимый диапазон

type
  Кости = range[1..20]  # 🎲 Допустимым значением являются только int от 1 до 20
var
  мой_бросок: Кости = 13

when компилироватьПлохойКод:
  мой_бросок = 23  # Error!

# Массивы

type
  СчетчикБросков = array[Кости, int]             # Массивы фиксированной длины и
  ИменаНаправлений = array[Направление, string]  # индексируются любым порядковым типом.
  Истины = array[42..44, bool]
var
  счетчик: СчетчикБросков
  направления: ИменаНаправлений
  возможны: Истины

возможны = [false, false, false]  # Массивы создаются литералом [V1,..,Vn]
возможны[42] = true

направления[нСевер] = "ОО. Великий белый Север!"
направления[нЗапад] = "Нет, не иди туда."

мой_бросок = 13
счетчик[мой_бросок] += 1
счетчик[мой_бросок] += 1

var ещеМассив = ["Идекс по умолчанию", "начинается с", "0"]

# Доступны другие структуры данных, в том числе таблицы, множества,
# списки, очереди и crit-bit деревья.
# http://nim-lang.org/docs/lib.html#collections-and-algorithms (EN)

#
# IO и поток управления выполнением
#

# `case`, `readLine()`

echo "Читали какие-нибудь хорошие книги в последнее время?"

case readLine(stdin)
of "нет", "Нет":
  echo "Пойдите в свою местную библиотеку."
of "да", "Да":
  echo "Тогда продолжим"
else:
  echo "Здорово!"

# `while`, `if`, `continue`, `break`

import strutils as str  # http://nim-lang.org/docs/strutils.html (EN)
echo "Я загадало число между 41 и 43. Отгадай!"
let число: int = 42
var
  ввод_догадка: string
  догадка: int

while догадка != число:
  ввод_догадка = readLine(stdin)

  if ввод_догадка == "": continue  # Пропустить эту итерацию

  догадка = str.parseInt(ввод_догадка)

  if догадка == 1001:
    echo("AAAAAAGGG!")
    break
  elif догадка > число:
    echo("Неа. Слишком большое.")
  elif догадка < число:
    echo(догадка, " это слишком мало")
  else:
    echo("Точнооооо!")

#
# Итерации (циклы)
#

for i, элем in ["Да", "Нет", "Может быть"]:  # Или просто `for элем in`
  echo(элем, " по индексу: ", i)

for ключ, значение in items(@[(человек: "You", сила: 100), (человек: "Me", сила: 9000)]):
  echo значение

let мояСтрока = """
<пример>
`строки` для
тренировки
""" # Многострочная "сырая" строка

for строка in splitLines(мояСтрока):
  echo(строка)

for i, симв in мояСтрока:     # Индекс и символ. Или `for j in` только для символов
  if i mod 2 == 0: continue   # Компактная форма `if`
  elif симв == 'X': break
  else: echo(симв)

#
# Процедуры
#

type Ответ = enum оДа, оНет

proc спрос(вопрос: string): Ответ =
  echo(вопрос, " (д/н)")
  while true:
    case readLine(stdin)
    of "д", "Д", "да", "Да":
      return Ответ.оДа  # Перечисления могут быть квалифицированы
    of "н", "Н", "нет", "Нет":
      return Ответ.оНет
    else: echo("Поточнее, да или нет")

proc добавьСахар(количество: int = 2) =   # Значение по умолчанию 2, ничего не возвращает
  assert(количество > 0 and количество < 9000, "Диабет ☠")
  for a in 1..количество:
    echo(a, " кубик...")

case спрос("Сахарку?")
of оДа:
  добавьСахар(3)
of оНет:
  echo "Ну немнооожко!"
  добавьСахар()
# Здесь нет необходимости в `else`. Возможны только `да` и `нет`.

#
# FFI (интерфейс внешних функций)
#

# Так как Nim компилируется в C, то FFI делается очень просто:

proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.}

let cmp = strcmp("C?", "Легко!")

Кроме того, Nim выделяется среди себе подобных метапрограммированием, производительностью, функциями этапа компиляции.

Дальнейшее чтение (EN)


Хотите предложить свой перевод? Может быть, улучшение перевода? Откройте Issue в репозитории GitHub или сделайте pull request сами!

Первоначально предоставлено автором Jason J. Ayala P., и обновлено 3 авторами.