# about the Rust この document の方向性。 > 言語コンセプトですね。 > 簡単に言えば、この言語を使うと何が嬉しいんだっけ?というやつです。 ## この document の reference ではなく、読み物としての link 集 - [The Rust Programming Language 日本語版](https://doc.rust-jp.rs/book-ja/) - [DRY - Rust を始めるための資料集](https://blog-dry.com/entry/2021/01/23/141936) - [Zenn - Rust 入門](https://zenn.dev/mebiusbox/books/22d4c1ed9b0003) - [Zenn - RustCoder AtCoder と Rust で始める競技プログラミング入門](https://zenn.dev/toga/books/rust-atcoder) - [Zenn - Rust は何を解決しようとしたのか; メモリとリソースと所有権](https://zenn.dev/karno/articles/630a64fbc9c65e29b566) - [いもす研 - Rust は何が新しいのか(基本的な言語機能の紹介)](https://imoz.jp/note/rust-functions.html) ## Rust の特徴や pros ### Package 周り - `rustup` - Rust のツールチェーン - Rust コンパイラ (`rustc`) や language server などを install するときに使う - `cargo` - Package マネージャー / build tool --- - 基本的に `rustup` は最初の install 時のみ使う。基本的な作業としては `cargo` を使う - `cargo` 自体は binary - コンパイラと同じ母体が開発しているためグダグダにならない (pip とか npm / yarn みたいなことがない) - パッケージレジストリも今の所唯一 (crates.io) - 最近の他言語の Package マネージャー / build tool がやれることは大体できる - セマンティックバージョニングで依存関係を管理 - git からのソースを取得 - 依存関係のプロジェクト毎の隔離 - not Python pip - lock ファイルでの再現性のあるビルド - 設定を殆ど書かなくて良い - ライブラリとバイナリの両方を扱える - テスト用などの開発時専用の依存関係を書ける - 面倒を見る範囲が広い - スケルトン生成 (`cargo new`) - エラーチェック (`cargo check`) - ビルド (`cargo build`) - 実行 (`cargo run`) - テスト (`cargo test`) - ドキュメント生成 (`cargo doc`) - パッケージの release (`cargo publish`) - パッケージバイナリのインストール (`cargo install`) - formatter としては、`rust-lang/rustfmt` という同じ母体のデファクトツールが有る ### Documentation comment - `///` や `//!` といった通常のコメント (`//`) とことなる特殊なコメントを書ける - `cargo doc` で HTML 形式のドキュメントを自動生成できる - コメント内で markdown が書ける - コメント内に test code が書けて実行できる - すべて言語組み込みとして実装されている ### Test - 言語組み込みでテストモジュールが含まれている `cargo test` - 単体テストは基本的に同ファイル内に書く - もっと上の layer のテストは `tests` directory に書く - test library としての基本的な機能は大体揃っている - `cargo bench` というベンチマーク用のコマンドもある ### Build - `cargo build` で library や binary を生成する - `cargo build --target` でクロスコンパイルできる - libc とかに静的リンクした binary がほしければ、`x86_64-unknown-linux-musl` を target にすれば良い - Docker の scratch image とかに、そのまま binary を add して動かせる ```bash $ rustup target list | pr -w 90 --column=3 aarch64-apple-darwin i586-unknown-linux-musl thumbv6m-none-eabi aarch64-apple-ios i686-linux-android thumbv7em-none-eabi aarch64-fuchsia i686-pc-windows-gnu thumbv7em-none-eabihf aarch64-linux-android i686-pc-windows-msvc thumbv7m-none-eabi aarch64-pc-windows-msvc i686-unknown-freebsd thumbv7neon-linux-androideabi aarch64-unknown-linux-gnu i686-unknown-linux-gnu thumbv7neon-unknown-linux-gnu aarch64-unknown-linux-musl i686-unknown-linux-musl thumbv8m.base-none-eabi aarch64-unknown-none mips-unknown-linux-gnu thumbv8m.main-none-eabi aarch64-unknown-none-softfloa mips-unknown-linux-musl thumbv8m.main-none-eabihf arm-linux-androideabi mips64-unknown-linux-gnuabi64 wasm32-unknown-emscripten arm-unknown-linux-gnueabi mips64-unknown-linux-muslabi6 wasm32-unknown-unknown arm-unknown-linux-gnueabihf mips64el-unknown-linux-gnuabi wasm32-wasi arm-unknown-linux-musleabi mips64el-unknown-linux-muslab x86_64-apple-darwin arm-unknown-linux-musleabihf mipsel-unknown-linux-gnu x86_64-apple-ios armebv7r-none-eabi mipsel-unknown-linux-musl x86_64-fortanix-unknown-sgx armebv7r-none-eabihf nvptx64-nvidia-cuda x86_64-fuchsia armv5te-unknown-linux-gnueabi powerpc-unknown-linux-gnu x86_64-linux-android armv5te-unknown-linux-musleab powerpc64-unknown-linux-gnu x86_64-pc-windows-gnu armv7-linux-androideabi powerpc64le-unknown-linux-gnu x86_64-pc-windows-msvc armv7-unknown-linux-gnueabi riscv32i-unknown-none-elf x86_64-rumprun-netbsd armv7-unknown-linux-gnueabihf riscv32imac-unknown-none-elf x86_64-sun-solaris armv7-unknown-linux-musleabi riscv32imc-unknown-none-elf x86_64-unknown-freebsd armv7-unknown-linux-musleabih riscv64gc-unknown-linux-gnu x86_64-unknown-illumos armv7a-none-eabi riscv64gc-unknown-none-elf x86_64-unknown-linux-gnu (ins armv7r-none-eabi riscv64imac-unknown-none-elf x86_64-unknown-linux-gnux32 armv7r-none-eabihf s390x-unknown-linux-gnu x86_64-unknown-linux-musl asmjs-unknown-emscripten sparc64-unknown-linux-gnu x86_64-unknown-netbsd i586-pc-windows-msvc sparcv9-sun-solaris x86_64-unknown-redox i586-unknown-linux-gn ``` ### IDE - vscode に `rust` という拡張を入れる - language server や formatter と連携しつついい感じにやってくれる - コンパイラによるエラーもコード上に表示してくれる - 基本的に Rust はコンパイラから怒られなければなんとかなる言語 ### 後方互換性 - Edition という概念で後方互換性を維持している - `Cargo.toml` という node.js でいう `package.json` みたいなファイルに `edition = 2018` のように書く - 現在の edition は、2015 と 2018 のみ - edition が違うからといって、別のコンパイラを使うみたいなことはない ### 言語仕様というか言語コンセプト - 性能、メモリ安全性、安全な並行性を目指して設計されたマルチパラダイム言語 - GC なしでのメモリ安全性 - 値と変数に所有権や lifetime という概念を導入して、コンパイル時にチェックする - 表面上は手続き型、小さな単位でのコードの書き方は関数型 (あんまりゴリゴリのやつではなくイテレータとかラムダ式とかライトなやつ) - 変数は基本的に immutable、可変変数を扱いたい場合は `mut` keyword を使う - 基本的に「文」ではなく「式」 (e.g. if 式) - 静的型付けかつ強い型付け - コンパイル時に全ての型を決定しなければならない - ただ、強い型推論があるため、変数の型を一々書くことはない - 型システムとしては impl、trait, struct, enum を基本として、Generics も使える - 例外はない ### 例外処理 - 戻り値を使ってエラーハンドリングする (Go みたいに) - 基本的に関数は `Result<T, E>` という Result 型 (enum) を返すように書く ```rust enum Rusult<T, E> { Ok(T), Err(E) ``` - 厳密には match 式を使ってエラー処理を書いていく - 回復不能なエラーとして `panic!` マクロが用意されている - 巻き戻してメモリの片付けなどして異常終了する --- - 流石に全部独自 Error を定義したり、match 式で判定するのは面倒なため、色々なシンタックスシュガーが用意されている - `?` 演算子 - 値が `Err` なら即座に return する (例外のようなもの) - `and_then` や `unwrap` のようなメソッド - `anyhow` や `thiserror` といった、抽象的なエラー型を集めたり生成するライブラリ --- - ちなみに null も存在しない - `Option<T>` という Option 型 (enum) を使う ```rust enum Option<T> { None, Some(T), } ``` - Result も Option の両方ともちゃんと解決しない場合、コンパイラから怒られる ### 色々なライブラリ - 乱数生成 - rand - 正規表現 - regex - 時刻操作 - chrono - ロギング - log - json/yaml 周り - serde - 良く出来てる - argument parser - clap - web framework - https://github.com/flosse/rust-web-framework-comparison - actix_web ってのがデファクト - マルチスレッド化はちゃんと書かないといけない ### その他 - 時間がなかったもの - WebAssembly - 並列プログラミング (async / await) - Rust から C++ を呼ぶ