2019年9月にそっとメジャーバージョンが出ていたNimlangでちょいちょい遊んでいく。
Rust勢力に押し流されそうだったところに来たから本気で嬉しい。。
今golangで作ってるgRPC基板をnimで書き換えてやろうかとか思ったけど、NimでのgRPClibは「C++の資源そのまま使うのムズイっぽいからかなり大変やで」ってなんか書いてあってその、一旦無かったことに。
こういうのって追加したい項目が増えてきた時、記事分けるのと編集追記するのとどっちがええんやろう
使用したもの
nim ver 1.0
ところで何この記事
シンタックスやらなにやら確認中に「ほー」と思った部分を適当に並べます。
つまり、深いところまでやらないやつです
関係ないですがqiitaでインラインコード書こうとしてslackのと混ざって半角スペースあけてしまう病、ありませんか
シンタックスハイライトにnimがもうあるのは感動しました
とりあえず
lowerCamelが推奨されるようです。
あと、インデントはスペースのみで、\t
だとコンパイルが通らない模様。
当該記事とは関係ないですがWindowsプログラミングをメインでやってる方はタブ文字派多くて、unix/linuxだとスペース派が多い印象なんですけどどうなんでしょうね。
ちなみに自分は大昔に何だったかのソフトウェアがタブ文字のせいで機嫌を損ねた経験以来特に強い理由が無い限りはスペース派です。
コンパイル&実行
読めばまあ書いてあるんですが、とりあえず今現在は
nim c -r --verbosity:2 [[path/to/nimsrc]]
で。
verbosity2にするとコンパイル時の統計データと他にコンパイルした外部モジュール吐いてくれるので、ローカル開発段階ではとりあえず2でいいかなと。
省略すると1になるようです。1は統計とあとLint的な警告(Hint)を吐かないのかな。
挙動だけとりあえず見たいとかなら0で良いでしょう。あんまり余計なものを吐きません。
他、-d:release
つけるとリリースビルド(恐らく中間出力されるCソースが最適化されてる)になったり、
標準モジュールのSSL関連メソッド使いたかったら-d:ssl
つけなさいってあったりとオプション多め。
SSLのほうは全く検証してないので今度やります。
関数(一部)
ぷらぐま
素晴らしすぎる記事を発見したのでプラグマ関係は上記記事見れば良いかと思います。
また、この記事内ではABI気にするほどのことはしません
一応ごく簡単な一例で{.discardable.}
を
proc test: bool = true
test() # => error
これはコンパイル通りません。戻り値がある関数の戻り値をdiscard
無しで虚空に消すことは出来ません。
そこで
proc test: bool {.discardable.} = true
test()
こうすると通ります。これは「戻り値があるけどdiscard
なしでの呼び出しを許可する」って感じです。
ただこれが乱発される環境って想像できないけど。
関連していわゆるreturn void
な関数を呼ぶ時も、
proc test = echo "yes"
var foo = test() # => error
これもコンパイル通りません。void
は受け取れません。nil
が返りそうな気がした人はその気分を忘れましょう。
ちなみに関数定義時、引数がない場合はカッコ省略できるようです。ただ、呼び出し側はカラのカッコ要ります。
戻り値
暗黙に宣言されているresultちゃん
いろんな記事で言及されてますが、Nimさんのprocにはresult
って名前の変数が暗黙に宣言
されています。
そして返却するものを明示しなかった場合、暗黙でそのresult
が返却されます。
proc test1(): string =
"aaa"
proc test2(): string =
result = "aaa"
return
proc test3(): string =
var result = "bbb"
echo test1() # => aaa
echo test2() # => aaa
echo test3() # =>
rubyのように「最後に評価したもの」というよりは、「返すものが指定されていない場合、resultの中身が返る。returnが無い場合、最後に評価したものをresultに暗黙に代入する」って感じ…なのですが、test3のように同名で宣言しなおした場合、勝手に返却される能力は失われます。
個人的にはresultを返す場合であってもreturnを省略せずに書くほうが「何を返す場合でもreturnと変数名を省略するな」って一言で終わるので良いんじゃねえかなあって感があります。
複数の戻り値
rubyだと配列で返却されますよね。golangだとあれ内部的にどうなってるのかまではわかりませんが異なる型であっても複数の戻り値をいっぺんに返せます。
nimの場合だと、フィールド名を省略したタプルを使って実現する感じです。これがグッドノウハウなのかはちょっとわかりませんが…
proc test(): (string,int) =
var a = "aaa"
var b = 777
return (a, b)
var foo = test()
echo foo # => ("aaa", 777)
echo foo[0] # => "aaa"
echo foo[1] # => 777
変数
var/let/constを利用します。js?と思ってしまいますがjsのそれとは結構違います。っていうかjsが特殊ですね。
const
いわゆるコンパイル時に値が確定している必要がある定数です。javascriptのconstは単に再代入不可であるというだけで、コンパイル時に確定している必要はありません。
const foo = "oh, yes!"
これは通ります。が、
import os
const yyy = os.commandLineParams()[0]
これは通りません。cannot evaluate at compile time
って言われます。
定数に関数
rubyやgoだと通らない(関数を解釈する前に定数を解釈しているからと思う)んですが、
import os
import strutils
proc test1(): int =
result = 1 + 1
proc test2(): int =
var a = parseInt(os.commandLineParams()[0])
result = 1 + 1 + a
const foo = test1() # => 通る
# const foo = test2() => cannot evaluate at compile time
ただ個人的には可能だったところで出来ればやめてくれと言いたいところではあります
var
再代入可能な変数。jsで言うところのletですね。宣言時に型が自明な場合は型名を省略できます。
ちなみに、const/letでも可能ですが
var
a, b: int
c, d = (2, 3)
こんなんも出来ます。
let
constと同じですがコンパイル時に値が確定しなくても良い変数です。
import os
let yyy = os.commandLineParams()[0]
通ります。
次は
文字列関係で色々書きたいけどにちようびがおわってしまうのでまた今度