Skip to content

Instantly share code, notes, and snippets.

@eggplants
Last active July 3, 2022 12:31
Show Gist options
  • Save eggplants/5d9b0e83ff4ad4025706e7a5b0080a4d to your computer and use it in GitHub Desktop.
Save eggplants/5d9b0e83ff4ad4025706e7a5b0080a4d to your computer and use it in GitHub Desktop.
Learn Nim in 5 minutes ( https://learnxinyminutes.com/docs/nim , accessed-at: 2022-06-26) の日本語訳
# 一行だけのコメントは `#` から始まります。
#[
これは複数行のコメントです。
Nimでは、複数行のコメントはネスト可能で、#[ に始まり
... ]# に終わります。
]#
discard """
これでも複数行のコメントとして機能します。
正しくパースできない、壊れたコードに使うと良いです。
"""
var # 変数の宣言や代入時には、
letter: char = 'n' # 型注釈があってもなくても良いです。
lang = "N" & "im"
nLength: int = len(lang)
boat: float
truth: bool = false
let # 一度きりの宣言や代入の際には let を使いましょう。
legs = 400 # 👈の変数 `legs` は不変(immutable, 再代入が不可能)です。
arms = 2_000 # 数字内の `_` は無視されます。でかい数字を書くのに便利です。
aboutPi = 3.15
const # 定数はコンパイル時に計算されます。
debug = true # これはコンパイル時定数(C++のconstexpr文)として便利な特性を発揮します。
compileBadCode = false
when compileBadCode: # `when` はいわゆるコンパイル時 `if` (C++のconstexpr if文) です。
legs = legs + 1 # 👈は誤ったコードですが、絶対にコンパイルされることはないです。
const input = readline(stdin) # Const 変数はコンパイル時に値がわかってないといけません。
discard 1 > 2 # ⚠Nimのコンパイラは式の結果がどこからも使われないままだとキレます。
# `discard` で無視できます。
#
# データ構造
#
# タプル (tuple)
var
child: tuple[name: string, age: int] # タプルはフィールド名と順序の両方を持ちます。
today: tuple[sun: string, temp: float]
child = (name: "Rudiger", age: 2) # 代入は `()` リテラルか個別のフィールドを使って
today.sun = "Overcast" # 一度だけ行えます。
today.temp = 70.1
# シーケンス (seq)
var
drinks: seq[string]
drinks = @["Water", "Juice", "Chocolate"] # `@[値1,..,値n]` はシーケンスリテラルになります。
drinks.add("Milk")
if "Milk" in drinks:
echo "We have Milk and ", drinks.len - 1, " other drinks"
let myDrink = drinks[2]
#
# 型を定義してみる
#
# 自分で型を定義して、コンパイラに仕事をさせてみましょう。
# 静的片付けを強力かつ扱いやすいものにできます。
type
Name = string # 型エイリアスは元の型と相互変更可能だけど、
Age = int # よりわかりやすい (descriptive) 新たな型をあなたにもたらします。
Person = tuple[name: Name, age: Age] # データ構造も定義できます。
AnotherSyntax = tuple
fieldOne: string
secondField: int
var
john: Person = (name: "John B.", age: 17)
newage: int = 18 # `int` 型より `Age` 型の方がいいのですが…
john.age = newage # まだこれでも動きます。 `int` 型は `Age` 型の同意語 (synonym) ですからね。
type
Cash = distinct int # `distinct` で、新しい型を元の型と
Desc = distinct string # 「不適合なもの」として宣言できます。
var
money: Cash = 100.Cash # `.Cash` で `int` 型のものをユーザ定義の型(ここでは `Cash`型)にできます。
description: Desc = "Interesting".Desc
when compileBadCode:
john.age = money # !エラー! `age` は `int` 型で `money` は `Cash` 型です。
john.name = description # コンパイラくん「ありえんだろ!」
#
# もっと!型とデータ構造
#
# 列挙型 `enum` は、限られた数の値のうちの1つだけを持てます。
type
Color = enum cRed, cBlue, cGreen
Direction = enum # もう一つの書き方
dNorth
dWest
dEast
dSouth
var
pixel = cGreen # `pixel` は `Color` 型であり、 `cGreen` 型を持っています。
orient = dNorth # `orient` は `Direction` 型であり、`dNorth` 型を持っています。
discard dNorth > dEast # `enum` 型は普通、順序型(ordinal type)です。
# 部分範囲型 `range[下限..上限]` は、 有効範囲を限定して指定できます。
type
DieFaces = range[1..20] # 有効な値は1〜20の `int` 型だけです。
var
my_roll: DieFaces = 13
when compileBadCode:
my_roll = 23 # !エラー!
# 配列 は `array[添字の型, 要素の型]` で宣言できます。
type
RollCounter = array[DieFaces, int] # `array` 型のものは可変長で、
DirNames = array[Direction, string] # 順序型ならどんなものでも添字にできます。
Truths = array[42..44, bool]
var
counter: RollCounter
directions: DirNames
possible: Truths
possible = [false, false, false] # [値1,..,値n]でリテラル配列を作成できます。
possible[42] = true
directions[dNorth] = "Ahh. The Great White North!"
directions[dWest] = "No, don't go there."
my_roll = 13
counter[my_roll] += 1
counter[my_roll] += 1
var anotherArray = ["Default index", "starts at", "0"]
# これらの他にも利用可能なデータ構造があります。
# テーブル (tables) 、 集合 (sets) 、 リスト (lists) 、キュー (queues) 、基数木 (crit bit trees) ...
# 詳細👉 http://nim-lang.org/docs/lib.html#collections-and-algorithms
#
# 入出力と制御構文
#
# `case` + `readLine()`
echo "Read any good books lately?"
case readLine(stdin)
of "no", "No":
echo "Go to your local library."
of "yes", "Yes":
echo "Carry on, then."
else:
echo "That's great; I assume."
# `while` + `if` + `continue` + `break`
import strutils as str # 詳細👉 http://nim-lang.org/docs/strutils.html
echo "I'm thinking of a number between 41 and 43. Guess which!"
let number: int = 42
var
raw_guess: string
guess: int
while guess != number:
raw_guess = readLine(stdin)
if raw_guess == "": continue # 現在の繰り返しを飛ばす
guess = str.parseInt(raw_guess)
if guess == 1001:
echo("AAAAAAGGG!")
break
elif guess > number:
echo("Nope. Too high.")
elif guess < number:
echo(guess, " is too low")
else:
echo("Yeeeeeehaw!")
#
# 反復 (Iteration)
#
for i, elem in ["Yes", "No", "Maybe so"]: # 単に `for elem in` でもOK
echo(elem, " is at index: ", i)
for k, v in items(@[(person: "You", power: 100), (person: "Me", power: 9000)]):
echo v
let myString = """
an <example>
`string` to
play with
""" # 複数行の raw 文字列
for line in splitLines(myString):
echo(line)
for i, c in myString: # それぞれ添字と文字をとりだす。文字だけなら `for j in` でOK
if i mod 2 == 0: continue # `if` のコンパクトな書き方
elif c == 'X': break
else: echo(c)
#
# プロシージャ (Procedures, 一般複数の処理を一つの関数に固めたもの)
#
type Answer = enum aYes, aNo
proc ask(question: string): Answer =
echo(question, " (y/n)")
while true:
case readLine(stdin)
of "y", "Y", "yes", "Yes":
return Answer.aYes # `Enum` 型で値の型を限定できます。
of "n", "N", "no", "No":
return Answer.aNo
else: echo("Please be clear: yes or no")
proc addSugar(amount: int = 2) = # 引数 `amount` の デフォルト値は 2で、返り値はありません。
assert(amount > 0 and amount < 9000, "Crazy Sugar")
for a in 1..amount:
echo(a, " sugar...")
case ask("Would you like sugar in your tea?")
of aYes:
addSugar(3)
of aNo:
echo "Oh do take a little!"
addSugar()
# ここで `else` 節は必要ありません。`yes` か `no` だけが可能です。
#
# FFI (Foreign function interface、他言語の関数を呼び出す機能)
#
# Nim は C言語にコンパイルされるため、FFIは容易です。
proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.}
let cmp = strcmp("C?", "Easy!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment