龍虎氏の記事についてのコメント。
まず最初にRustによるコードとC言語によるコードを並べてみよう。
両者とも見た目は確かに良く似ていると思う。
「見かけ」に関して言えば、確かにRustは「Cっぽく見せる」ようにしている。
ただし、細かいトコでは当然、色々と違いがあるんだ。
まずMain部分、なるほどFnって何だよw。
fnは予想通りfunction(関数)の事だ。ザックリ言っちゃえばRacketのdefine、Pythonのdefの類だと考えていい。あるいはJavaScriptのfunctionか。functionもどんどん縮めちゃってとうとう2文字だ(笑)。
いずれにせよ、関数定義用のキーワードだと考えていい。
そして実はこれがC言語にはないんだ。
この冒頭部分だけ、を比較すると、
// Rustfn main() {// C言語int main(void) {
と確かに似てるが、Rustが「mainと言う関数を定義しますよ」と言ってるのに対し、C言語は単に「構文構造上」関数定義になる。じゃあintは?と言うのはこれは関数定義ではなく、その関数が返す値の型を意味してる(結果、mainは整数型を返す関数、って事になる)。
Rustの場合、上のmain関数は返り値がないんで、どっちかっつーと手続き(プロシージャ)になってる。そして返り値がある場合、Cと違って、矢印を使った、一般的にアノテーションと呼ばれる形式で、返り値の型を指定する。
// 返り値の型が32ビット幅の整数型の場合fn five() -> i32 {5}
この辺は、C言語系に見せかけておいて実は全く違うんで覚えておこう(※1)。
そして()をつけてからの{か〜
main関数も関数である以上引数リストが必要・・・なんだけど、Racketだと無引数関数はこんなんだしな(笑)。
(define (main) ...
そうね、Racketやってたらフツーの言語の「引数リスト」ってピンと来ねぇよなぁ(笑)。
そういや、OCamlでも引数ってカッコ伴わなかったわ(笑)。
こう考えてみると、龍虎氏っていわゆる「フツーのプログラミング言語」ってやった事ねぇんだよな(ヲイ)。
なお、C言語の場合、仕様上、無引数関数の場合、定義時の引数リストのカッコ内にvoidを入れるお約束になっている。「何も置かない」ってのは仕様上非推奨なんだ。
(Rustみたいに空カッコで書く人がいまだ多いけど間違っている)
Println!は;してから}か〜
ここに注意!
ホントRustはC言語の「見た目」を良く真似してるんだけど、実はこのセミコロン(;)の意味がCとRustじゃ全然違うんだ。
Cだと「式の終わり」を意味してて、そこが無いと文法エラーになる。
一方、Rustは、実は一般的な明示的構文であるreturnが無い言語なんだ。
Rustはその代わり、式の終わりにセミコロンを置けばその返り値を無視し、セミコロンがない式が関数全体(あるいは構文)の返り値になる。
上で例に挙げたコードをもう一回見てみよう。
// 返り値の型が32ビット幅の整数型の場合fn five() -> i32 {5}
この本体の式である5の後ろにはセミコロンが置いてない。従って、ここでは5が返り値になる、ってわけだ。
件のFizzBuzzのコードでprintln!が形成する式にセミコロンが必要なのは、そこのmain関数が事実上プロシージャで返り値を必要としてないから、なんだ。
Elifじゃなくて以降は全部Elseで良いんだね、合理的。
この辺ちとPython混ざった判断だったかも(笑)。
と言うか、elifなんてヘンなキーワードってPythonくらいしかなくない(笑)?
多分。
Println!の変数挿入は"{}", nか〜
Pythonでも3.x以降すっかりお馴染みになったプレースホルダー({})だ。
多分ルーツはC#かね?非常に便利でエエもんです(笑)。
(もっとも、Lispではformatと~aがある場合が多いけど)
※1: Racketでも引数へ与える型、返り値の型、が分かってる場合、define/contractでアノテーションを使って静的型付け言語のように書く事が出来る。
また、Pythonで最近、静的言語ユーザーに応える為、関数アノテーションと言う機能を提供している。