Rust

私がRustを選んだ理由

久しぶりにgolangに行ったら、新しい1.6が来てたので入れた。順調に進化してるな。また触ってみるか。血圧管理アプリもgo製だしね。

ネットをうろうろしてたら、

実装言語を「Go」から「Rust」に変更、ゲーマー向けチャットアプリ「Discord」の課題とは

こんな記事に行き当たった。Goが採用してるGCが足枷になってるとな。Lispに源にするGCは、javaだとかrubyとかにも採用され、ユーザーをメモリー管理から解放してくれる希望の星とばかり思っていた。

けど、場合によっては邪魔になるとな。そう言えばjavaなんかは、並々ならぬ苦労をしてGCの挙動を隠すようにしてたね。この事情はrubyも同じだ。

大体、GoとRustはよきライバル関係にあるのだな。そう思って、もう少しggしてみると、

Rust,Go,Elixir,Kotlin次世代言語の魅力をCTOが語る

どこかの社長さんが21世紀言語を語っていた。そして、こんな記事もあったぞ。

次代を担う新プログラミング言語の使いどころ

幸いオイラーは、Rustなんて触った事が無い、原人。OpenBSDに来てたら触ってみるか、と言う他人まかせな賭けに出て見る。無いならスルーします。

って、有ったから、この記事を書いているんでしょ。

Install Rust

畳上の水練にならないように、処理システムを入れるのが最初の一歩です。

at OpenBSD

パッケージは4つに分解されてました。rustって奴が一番大きいから本体だろう。rust-gdbなんてのは、gdbのサポートなんだな。後の2つは何よ? portsの説明を参照。

DESCR-clippy
A bunch of lints to catch common mistakes and improve your Rust code.

DESCR-rustfmt
A tool for formatting Rust code according to style guidelines.

これを見ると、迷わず入れておkって類ですね。

それからemacsのサポートはどうか?ggると、色々な設定を施している方が多いけど、最初はそこまで凝らずに、basicなrust-modeだけを入れた。   第二歩目は、あれだ。

ob$ cat hoge.rs
fn main() {
    println!("Hello, world!");
}
ob$ rustc hoge.rs
ob$ ./hoge
Hello, world!

あれ? C語で必要だった、#include が不要になってるね。

ob$ ldd ./hoge | cut -b 50-

 GrpRef Name
 0      ./hoge
 0      /usr/lib/libpthread.so.26.1
 0      /usr/lib/libc++abi.so.3.0
 0      /usr/lib/libc.so.96.0
 0      /usr/libexec/ld.so
ob$ file hoge
hoge: ELF 64-bit LSB shared object, x86-64, version 1
ob$ ls -l hoge
-rwxr-xr-x  1 sakae  wheel  324832 Mar  9 08:03 hoge*

at debian

OpenBSDへのカウンターとしてリナ系にも入れるのが、オイラーの流儀。一穴はまずいですからね。

Webでアクセスしてインストールを選べば、rustupってコマンドで簡単に、開発環境をインストール出来る。このアプリが、アップデートにも対応してる。

Other installation methods こんな案内も有った。

debian:~$ du -sh .cargo/
144M    .cargo/
debian:~$ du -sh .rustup/
1.1G    .rustup/

普段使いのコマンド類は、.cargo/bin/に収まっている。が、それを下支えするライブラリィー類は、.rustupの中に格納されている。この.rustupは、見なかった事にしておくのが吉。 それから、これらが全て$home下に置いてある事に注目。全てユーザーの裁量でなんとか出来る。これは、派遣先とかで、こっそりと内職をやる時等、便利だぞ。敷居を下げて、拡散希望って、切なる願いがこもっております。

debian:z$ time rustc hoge.rs

real    0m12.282s
user    0m0.502s
sys     0m0.181s
debian:z$ ./hoge
Hello, world!
debian:z$ rm hoge
debian:z$ time rustc hoge.rs

real    0m0.604s
user    0m0.514s
sys     0m0.086s

お約束で初回は色々な準備が有る為、随分待たされる。2回目からは、許容範囲のコンパイル時間に落ち着く。そなら、mainは特別扱いか、調べてみる。

debian:z$ rustc hoge.rs
error[E0601]: `main` function not found in crate `hoge`
 --> hoge.rs:1:1
  |
1 | / fn foo() {
2 | |     println!("Hello, world!");
3 | | }
  | |_^ consider adding a `main` function to `hoge.rs`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0601`.

やはり特別扱い。C語の遺伝子を継承してるな。ここ見ろワンワンが示された。

debian:z$ rustc --explain E0601
No `main` function was found in a binary crate.

To fix this error, add a `main` function:

```
fn main() {
    // Your program will start here.
    println!("Hello world!");
}
```

If you don't know the basics of Rust, you can look at the
[Rust Book][rust-book] to get started.

[rust-book]: https://doc.rust-lang.org/book/

本嫁、本読めと言ってきたな。

debian:z$ ls -lh hoge
-rwxr-xr-x 1 sakae sakae 3.1M Mar 10 07:14 hoge*
debian:z$ ldd hoge
        linux-gate.so.1 (0xb7efc000)
        libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7e5d000)
        librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb7e52000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7e31000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb7e2b000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7c4d000)
        /lib/ld-linux.so.2 (0xb7efe000)

OpenBSDのrustが作ったバイナリーに比べて10倍も肥大化してる。

from source

バイナリーインストールは気味が悪いので、一応ソースに当たっておく。

rust-lang / rust

ninja って言う新種のbuildシステムが必要とか。

Ninja is yet another build system. It takes as input the interdependencies
of files (typically source code and output executables) and orchestrates
building them, quickly.

Ninja joins a sea of other build systems. Its distinguishing goal is to be
fast. It is born from my work on the Chromium browser project, which has
over 30,000 source files and whose other build systems (including one built
from custom non-recursive Makefiles) can take ten seconds to start building
after changing one file. Ninja is under a second.

WWW: https://ninja-build.org/

取り合えずソースをお取り寄せ。

debian:src$ du -sh rust/
5.0G    rust/

ぐちゃぐちゃやってると思ったら、こんなに肥大化してた。自前でコンパイルしたら、とんでもない時間がかかりそう。潔く諦めた。

book

rustは難しいので、資料はbookと言う名前で公開されてるっぽい。

プログラミング言語Rustのススメ これがエッセンスだな。

Rust入門  全体を俯瞰するのに便利

お気楽 Rust プログラミング超入門 こちらもお勧め

The Rust Programming Language日本語版 本家の資料が日本語化されてる

Rustの日本語ドキュメント/Japanese Docs for Rust 日本語資料の基点

Rustの本家 日本語がサポートされてるって、めちゃ感激。

この本家では、スペイン語やフランス語やロシア語等も有るけど、何故かドイツ語は無い。昔ドイツの人と交流した事が有るけど、皆英語は普通に使ってた。田舎のホテル兼居酒屋で、おばちゃんからも英語で話かけられたし。

ドイツ国内を旅行した時、やはり居酒屋で、よいぼれ爺さんにビールを奢ってもらった。 お前はヤーパンか、今度イタ公抜きで、もう一度戦争しようなんて、悪い冗談を言われた。

こう考えるとRustは、言語障害をかかえる国の人(正しく、オイラーみたいな奴)にも、手厚いサポートをしてファンを増やそうと言う心意気を感じるぞ。

compile ang go

goもそうであったように、プロジェクトを作って、そこでごにょごにょやるのが、現代風らしい。その為にはcargoって言うコマンドを使うとな。

ob$ cargo new hoge
     Created binary (application) `hoge` package
ob$ cd hoge/
ob$ tree
.
|-- Cargo.toml
`-- src
    `-- main.rs

1 directory, 2 files
ob$ time cargo r
   Compiling hoge v0.1.0 (/tmp/hoge)
    Finished dev [unoptimized + debuginfo] target(s) in 4.93s
     Running `target/debug/hoge`
Hello, world!
    0m04.95s real     0m00.21s user     0m03.45s system

newするとたたき台が出来る。r(un)すると、コンパイルされて、出来上がったバイナリーが実行される。初回は、やはり時間がかかる。

ob$ time cargo r
   Compiling hoge v0.1.0 (/tmp/hoge)
    Finished dev [unoptimized + debuginfo] target(s) in 0.56s
     Running `target/debug/hoge`
Hello, Rust
    0m00.58s real     0m00.18s user     0m00.59s system

ソースを変更してから、再実行。今度はすんなりだ。target/debug/hogeにバイナリーが出来上がるのだけど、サイズはリナのそれと比べて1/10のサイズだ。その違いは、/usr/lib/libc++abi.so.3.0が外のやつを使っている為と思われる。

crate

木箱って意味らしい。クレートと発音するそうな。箱だから何かが入っている。その何かは、好き者が開発したライブラリィー類。コンパイルする時の単位になる。ライブラリィーで機能豊富な場合、ファイルを分割する事がある。でも、そんな場合、ファイル単独のコンパイルでは意味をなさない。分割した物を全てコンパイルして(リンクして)、意味があるものになる。

The Rust community’s crate registry crate.io て所で、検索出来る。

ob$ cargo search rand
    Updating crates.io index
       Fetch [==============>                                        ]  27.42%

手元に持ってきて、検索するのが楽。indexは、$home/.cargo/registry/ 以下に置かれる。 何もかも .git に頼っていて、単一故障点だな。大丈夫か、おい。

ob$ cargo search rand
rand = "0.8.3"              # Random number generators and other randomness functionality.
  :
rand_mt = "4.0.1"           # Reference Mersenne Twister random number generators.
... and 491 crates more (use --limit N to see more)

for emacs

rust-lang / rust-mode これが標準設定?

;; rust-mode
(require 'rust-mode)
(add-hook 'rust-mode-hook
          (lambda () (setq indent-tabs-mode nil)))
(setq rust-format-on-save t)
(define-key rust-mode-map (kbd "C-c C-c") 'rust-run)

シンプルにrust-modeだけの仕様。requireは入れておかないと、シンボルが解決出来んと言うエラーになる(普通は、要らないんだけど、今回は特殊か)。

ob$ emacs src/main.rs
  :
ソースが見えたら、C-c C-c すると、画面が割れて、cargo runしてくれる。楽ちん。
-*- mode: compilation; default-directory: "/tmp/fuga/" -*-
Compilation started at Thu Mar 11 15:35:21

cargo run
   Compiling fuga v0.1.0 (/tmp/fuga)
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/fuga`
Hello, Emacs!

Compilation finished at Thu Mar 11 15:35:21

Rustの環境構築(Emacs) 凝った設定で、使いこなすの難しそう。

sample

実習

上で挙げた、時間計測ってのを、オイラーもやってみる。まず適当なプロジェクトを作るんだな。

ob$ cargo new zz
     Created binary (application) `zz` package
ob$ cd zz
ob$ emacs src/main.rs

main.rsを開いてから、取り合えずソースをコピペ。走らせてみると

cargo run
   Compiling zz v0.1.0 (/tmp/zz)
error[E0432]: unresolved import `quanta`
 --> src/main.rs:1:5
  |
1 | use quanta::Clock;
  |     ^^^^^^ use of undeclared type or module `quanta`

error: aborting due to previous error

初っ端からエラーの返礼。良くみると、該当するクレートが無いと言ってる。

ob$ cargo search quanta
quanta = "0.7.2"                  # high-speed timing facility
 :

この案内を、Cargo.tomlに書いておくんだな。

[dependencies]
quanta = "0.7.2"

これで走らせてみる。

ob$ cargo r
    Updating crates.io index
   Compiling bitflags v1.2.1
   Compiling libc v0.2.88
   Compiling atomic-shim v0.1.0
   Compiling once_cell v1.7.2
   Compiling raw-cpuid v9.0.0
   Compiling quanta v0.7.2
   Compiling zz v0.1.0 (/tmp/zz)
warning: variable does not need to be mutable
 --> src/main.rs:5:9
  |
5 |     let mut clock = Clock::new();
  |         ----^^^^^
  |         |
  |         help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 9.65s
     Running `target/debug/zz`
std::time:Instant::now() overhead = 1.718695873s
quanta::clock::now() overhead = 178.454077ms

quantaってのは、色々なモジュールに依存してる。勿論本体は陽にquantaに依存してる。それを解決(コンパイル)して、最後の2行が、実行結果。このソースの場合、mutは必要無いと、ご丁寧な提案が有った。

本体に依存したライブラリィーは、$home/.cargoの中に蓄えられるのね。 この実習で、大体の仕組みが分かったよ。

このソースでも使われているんだけど、printlnマクロのブレースフォルダーの指定が分からなかったので、先人の調べを借用した。

{Rust} 文字列のフォーマット指定(println! / format!)


This year's Index

Home