[Rust]インストールからHello world, Cargoを使ったプロジェクト管理入門

入門書として[The Rust Programming Language 日本語訳](https://doc.rust-jp.rs/book/second-edition/ch01-01-installation.html)から学んだアウトプットです。

# 環境
Archlinux

# Rustインストール

## インストーラースクリプトを使う
追記
最初OSのパッケージマネージャーを使う方法で試しましたが、下記に述べるエラー?というか一手間が発生したので、[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-01-installation.html)推奨の`curl https://sh.rustup.rs -sSf | sh`を使ったインストールスクリプトの方法を試します。

```shell-session
$ curl https://sh.rustup.rs -sSf | sh
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  /home/u1and0/.rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory located at:

  /home/u1and0/.cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /home/u1and0/.cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /home/u1and0/.profile
  /home/u1and0/.bash_profile

You can uninstall at any time with rustup self uninstall and
these changes will be reverted.

Current installation options:


   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>
# 対話的に聞いてくるので、Enter押すと(1)のデフォルト設定をしてくれる

info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-07-16, rust version 1.45.0 (5c1f21c3b 2020-07-13)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 12.2 MiB /  12.2 MiB (100 %)  10.9 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
 15.8 MiB /  15.8 MiB (100 %)  10.7 MiB/s in  1s ETA:  0s
info: downloading component 'rustc'
 47.6 MiB /  47.6 MiB (100 %)  10.9 MiB/s in  4s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: Defaulting to 500.0 MiB unpack ram
info: installing component 'clippy'
info: installing component 'rust-docs'
 12.2 MiB /  12.2 MiB (100 %)  12.1 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
 15.8 MiB /  15.8 MiB (100 %)  13.3 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
 47.6 MiB /  47.6 MiB (100 %)  13.5 MiB/s in  3s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'stable'

  stable installed - rustc 1.45.0 (5c1f21c3b 2020-07-13)


Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done
automatically.

To configure your current shell run source $HOME/.cargo/env
```

toolchain=stableを落としてきて、cargo, rust関連の実行ファイルをパスに追加してくれました。


## インストーラースクリプトを使わずOSのパッケージマネージャーを使う
`$ curl https://sh.rustup.rs -sSf | sh` を打てと書いてありますが、せっかくArchlinuxなんで`pacman`で環境構築してみます。

```
$ pacman -Syu rustup
```

archlinuxは古いものから新しいものまでpacmanで簡単にインストール・管理が出来るのがいいですね。
インストールしたらとりあえずバージョン確認。

```
$ rustc --version
error: no override and no default toolchain set
```

エラーでした。なんで？
**この辺からは[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-01-installation.html)に書いていないこと。**

そもそも`rustup`ってなんや
help見てみます。

```
$ rustup help
rustup 1.22.1 (2020-07-08)
The Rust toolchain installer

USAGE:
    rustup [FLAGS] [+toolchain] <SUBCOMMAND>
(snip...)
```

```
$ pacman -Qs rustup
local/rustup 1.22.1-1
    The Rust toolchain installer
```

rustupってtoolchainインストーラーなんだ。(toolchainってなんだ？とは思いつつ。)
つまりこのエラーはtoolchainがないから怒られているとうことで。helpに従い`rustup [toolchain]`をupdateしてみましょう。
次のコマンドで通りました。

```shell-session
$ rustup update stable
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-07-16, rust version 1.45.0 (5c1f21c3b 2020-07-13)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
12.2 MiB /  12.2 MiB (100 %)  10.7 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
15.8 MiB /  15.8 MiB (100 %)  10.5 MiB/s in  1s ETA:  0s
info: downloading component 'rustc'
47.6 MiB /  47.6 MiB (100 %)  10.7 MiB/s in  4s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: Defaulting to 500.0 MiB unpack ram
info: installing component 'clippy'
info: installing component 'rust-docs'
12.2 MiB /  12.2 MiB (100 %)   8.6 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
15.8 MiB /  15.8 MiB (100 %)  10.2 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
47.6 MiB /  47.6 MiB (100 %)  10.3 MiB/s in  4s ETA:  0s
info: installing component 'rustfmt'

stable-x86_64-unknown-linux-gnu installed - rustc 1.45.0 (5c1f21c3b 2020-07-13)

info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'
```

toolchainの種類は次のリンク先に書いてありました。
[rust-lang/rustup/README](https://github.com/rust-lang/rustup/blob/060192bd8089b4866f1571d85e85ca0264323233/README.md#the-toolchain-file)
> only contain the names of the three release channels, 'stable', 'beta', 'nightly',

Rust言語の開発者ではないので、stableを選択しました。

**[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-01-installation.html)に書いていないこと終わり**


```
$ rustc --version
rustc 1.45.0 (5c1f21c3b 2020-07-13)
```

無事、Rustが使えるようになったようです。

~~続いて、cargoのパスを追加していきます。~~
~~[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-01-installation.html)に書いてあることをアレンジして、~/.bashrcに下記を加えました。~~

~~```bash:~/.bashrc~~
~~# Rust path~~
~~[ -f "/usr/bin/cargo" ] && export PATH="$PATH:$HOME/.cargo/bin"~~
~~```~~

追記 OSのパッケージマネージャーを使うとグローバルのパス`/usr/bin`にインストールされるのでパスに加える必要はないでしょう。ということで削除しました。


## `curl...sh`を使った場合とOSのパッケージマネージャーを使った場合の違い
* `curl...sh`を使うと、toolchain(stableなど)を`rustup update stable`する必要がない(`curl ... | sh`がやってくれる)
* `curl...sh`を使うと、cargo, rustup, rustcなどの実行ファイルが`~/.cargo/bin`に入る
  * パッケージマネージャーを使って`rustup update stable`すれば`/usr/bin`や`/usr/sbin`下に入る
  * すなわち`curl...sh`を使うと全てのユーザーがrustを使えない(curl...shを使ったユーザーのみがrustを触れる)

```shell-session:curl...shを使った場合
$ ls ~/.cargo/bin
cargo*         cargo-fmt*   clippy-driver*  rust-gdb*   rustc*    rustfmt*
cargo-clippy*  cargo-miri*  rls*            rust-lldb*  rustdoc*  rustup*
```

* `curl...sh`を使うと、`~/.cargo/env`が作られる
  * `~/.cargo/env`はcargoやrustupの実行ファイルをパスに加えて実行できるようにするだけの設定です。

```~/.cargo/envの中身
export PATH="$HOME/.cargo/bin:$PATH"
```

`curl...sh`実行時に出る下記メッセージの通り、勝手に`~/.bash_profile`などにexport文が書き込まれるようです。

> This path will then be added to your PATH environment variable by
> modifying the profile files located at:
>
>   /home/u1and0/.profile
>   /home/u1and0/.bash_profile

これで次回shell立ち上げ時にcargo関連のパスが追加され、cargoやrustupを実行できるようになります。

`curl...sh`のインストールスクリプトを使う方法とOSのパッケージマネージャーを使う方法どちらが良いかは運用方法、好みによります。
OSのパッケージマネージャーを使えば、`pacman -Syu`したときに自動的に`rustup`もアップグレードしてくれますし、インストールスクリプトを使えば自分で`rustup update`を打つ必要があります。
(OSのパッケージマネージャーを使っても、`rustup自体`がアップグレードされるだけで、実質`rustup update`も打たなければなりませんが。)

どのユーザーがRustを使えるか、という点も異なる点の一つです。グローバルに使いたいのであればOSのパッケージマネージャー、1ユーザーだけ使えれば良いのであれば面倒の少ない`curl...sh`で良いのではないでしょうか。


# Hello world
最初のプログラム、Hello worldを書いていきます。

[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-02-hello-world.html)に従い、下記ディレクトリを作成、移動し、main.rsに書き込みました。

```shell-session
$ mkdir -p ~/Dropbox/Program/rust/hello_world; cd $_
$ nvim main.rs
```

```rust:main.rs
fn main(){
    println!("Hello world");
}
```

shell上でmain.rsをコンパイルし、生成されたバイナリを実行します。

```shell-session
$ rustc main.rs  # main.rsをコンパイルする
$ ls  # バイナリが生成されたことを確認
main
main.rs
$ ./main # バイナリ実行
Hello world
```

うまくHello worldが出力されました。


# Hello cargo

cargoの使い方を学びます。
cargoのバージョンを確認し、インストールされていることを確認します。

```shell-session
$ cargo --version
cargo 1.45.0 (744bd1fbb 2020-06-15)
```

Cargoを使用して新しいプロジェクトを作成します。
--bin引数をつけることでバイナリを作成するプロジェクトのテンプレートを使用します。

```shell-session
$ cargo new hello_cargo --bin
     Created binary (application) `hello_cargo` package
$ tree hello_cargo
hello_cargo
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
```

上記のようなディレクトリとファイルが作成されました。
tomlの中身を覗いてみます。

```toml:hello_cargo/Cargo.toml
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["u1and0 <e01.ando60@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
```

勝手にGitのユーザ名とかメールアドレスとか使われるんですねー。
main.rsの中身を覗いてみます。

```hello_cargo/src/main.rs
fn main() {
    println!("Hello, world!");
}
```

Cargoが勝手にHello worldプログラムを生成してくれています。
[入門書](https://doc.rust-jp.rs/book/second-edition/ch01-03-hello-cargo.html)の文章を引用します。

> Cargoは、ソースファイルがsrcディレクトリにあることを期待します。プロジェクトの最上位のディレクトリは、 READMEファイル、ライセンス情報、設定ファイル、あるいは、他のコードに関連しないもののためのものです。 Cargoを使用すると、プロジェクトを体系化する手助けをしてくれます。


## Cargoプロジェクトをビルドし、実行する

### コンパイルする
Cargoプロジェクトのディレクトリ上で`cargo build`コマンドを打ちます。

```shell-session
$ cargo build
   Compiling hello_cargo v0.1.0 (/home/u1and0/Dropbox/Program/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_cargo-87a9db45987e9851
        │   └── hello_cargo-87a9db45987e9851.d
        ├── examples
        ├── hello_cargo  # コンパイルされた実行ファイル
        ├── hello_cargo.d
        └── incremental
            └── hello_cargo-szy1czdxg7sc
                ├── s-fpk74m1exc-85ppht-1fjb5q50dnnhg
                │   ├── 1gm6s9z6a68yb6gt.o
                │   ├── 24lg2nh8sairvn1p.o
                │   ├── 2i3icgmskvbcs2r6.o
                │   ├── 4tdo6t3jaqdcmc89.o
                │   ├── 4viuo6i1wu42msnb.o
                │   ├── dep-graph.bin
                │   ├── geox6bxp965pvuc.o
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-fpk74m1exc-85ppht.lock

9 directories, 17 files
```

随分ディレクトリやファイルが増えました。
コンパイルされた実行ファイルは`target/debug`の下にあります。

### コンパイルしてから実行する
`cargo build`はコンパイルまでですが、`cargo run`を使えばコンパイルから実行までをワンコマンドでできます。

```
$ cd ..
$ rm -rf hello_cargo
$ cargo new hello_cargo --bin
$ cd hello_cargo
$ # 上記でbuildする前の状態までディレクトリの状態を戻してます。
$ cargo run
   Compiling hello_cargo v0.1.0 (/home/u1and0/Dropbox/Program/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/hello_cargo`
Hello, world!
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_cargo-87a9db45987e9851
        │   └── hello_cargo-87a9db45987e9851.d
        ├── examples
        ├── hello_cargo
        ├── hello_cargo.d
        └── incremental
            └── hello_cargo-szy1czdxg7sc
                ├── s-fpk7k06p9o-kzim4w-1fjb5q50dnnhg
                │   ├── 1gm6s9z6a68yb6gt.o
                │   ├── 24lg2nh8sairvn1p.o
                │   ├── 2i3icgmskvbcs2r6.o
                │   ├── 4tdo6t3jaqdcmc89.o
                │   ├── 4viuo6i1wu42msnb.o
                │   ├── dep-graph.bin
                │   ├── geox6bxp965pvuc.o
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-fpk7k06p9o-kzim4w.lock

9 directories, 17 files
```

`cargo run`すると`cargo build`のときと同じようにディレクトリとファイルを作成し、Hello worldを実行します。

### コンパイル可能か確認する
`cargo check`コマンドは迅速にコードを確認しコンパイル出来ることを確かめますが、実行可能ファイルは生成しません。
`cargo build`のように実行可能ファイルを生成しないので、`cargo build`より高速です。
プログラムが実行可能かどうかを確かめながら組み立てるために`cargo check`を定期的に実行しながらコーディングします。

## まとめ
* `rustup`: toolchainインストーラー
* `rustup update stable`: stable toolchainをアップデートする
* `rustc`: コンパイラ
* `rustc main.rs`: main.rsをコンパイルする
* `cargo build`: cargoでコンパイル
* `cargo run`: cargoでコンパイルから実行
* `cargo check`: cargoでコンパイルできることを確認する(高速)