Open9

Rustの導入と入門

shimakaze_softshimakaze_soft

RustのWeb アプリケーションフレームワーク・ライブラリ

  • actix-web
  • Rocket
  • warp
  • Axum
  • tide
shimakaze_softshimakaze_soft

Rustは、Rustのバージョンと関連するツールを管理する、rustupというコマンドラインツールを使用してダウンロードする。

LinuxとmacOSでのrustupのインストール方法

$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh

このコマンドはスクリプトをダウンロードし、rustupツールのインストールを開始し、Rustの最新の安定版をインストールする。

インストールがうまく行けば、以下の行が表示されるはずです。

Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, run:
source "$HOME/.cargo/env"

以下を必ず実行してください。

$ source "$HOME/.cargo/env"

インストール完了後にシェルを再起動するか、上記のコマンドで環境設定を反映するとRustのコンパイル環境が有効になる。

https://doc.rust-jp.rs/book-ja/ch01-01-installation.html#linuxとmacosにrustupをインストールする

Rustの開発環境において、全てのツールは~/.cargo/binディレクトリにインストールされます。ここに以下を含むRustのツールチェーンが置かれる。

  • rustc
  • cargo
  • rustup

以下のコマンドで.cargo/binが表示されるはずです。

$ echo $PATH|grep cargo

以下のコマンドも成功するはずです。

$ rustc --version

https://www.rust-lang.org/ja/learn/get-started

Rustには3種類の配布用チャネルが用意されています。

  • stable: 安定リリース版
  • beta: 次期バージョンに向けたベータ版
  • nightly: 開発版

rustupコマンドを使ってインストールする。

$ rustup install stable
shimakaze_softshimakaze_soft

Rustビルドツールおよびパッケージマネージャ

Rustupをインストールすると、Rustのビルドツール及びパッケージマネージャであるCargoの最新安定版が同時に手に入ります。

  • プロジェクトのビルドにはcargo build
  • プロジェクトの実行にはcargo run
  • プロジェクトのテストにはcargo test
  • プロジェクトのドキュメントのビルドにはcargo doc
  • ライブラリをcrates.ioに公開するにはcargo publish

RustとCargoがインストールされたことを確かめるには、ターミナルで以下を実行します。

$ cargo --version

VS CODEの公式サポートの拡張ツール

https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer

shimakaze_softshimakaze_soft

Hello, Worldを作成

cargo newコマンドで新しいプロジェクトを作成します。

$ cargo new --bin hello-rust

これでhello-rustという新しいディレクトリが作られ、以下のファイルが置かれる。

$ tree
.
├── Cargo.toml
└── src
    └── main.rs
  • Cargo.toml : Rust用のマニフェストファイルで、プロジェクトの設定ファイル。プロジェクトのメタデータに加え依存関係も記録される。

  • src/main.rs : アプリケーションのコードを書く場所

cargo runコマンドで実行する。
デフォルトでデバッグ用ビルドになるので、--release オプションを指定してリリース用ビルドにしてみる。

$ cargo run
   Compiling hello-rust v0.1.0
    Finished release [optimized] target(s) in 0.35s
     Running `target/release/hello-rust`
Hello, world!

$ cargo run --release

Rust製のツールをインストール

プロジェクトの作成や実行で使用したcargoの install コマンドを使うと、Rust製のツールを簡単にインストールできる。

以下は普段使っていて便利なRust製のツール

ripgrep

概要: 検索ツール。 grep みたいな感じです、とにかく速い

  • インストール: cargo install ripgrep
  • リポジトリ: GitHub - BurntSushi/ripgrep: ripgrep recursively searches directories for a regex pattern

exa

概要: ファイル列挙ツール、 ls みたいな感じです。ツリー表示できて便利

  • インストール: cargo install exa
  • リポジトリ: GitHub - ogham/exa: Replacement for 'ls' written in Rust.

fd

概要: ファイル検索ツール、 find みたいな感じです、これも速い

  • インストール: cargo install fd-find
  • リポジトリ: GitHub - sharkdp/fd: A simple, fast and user-friendly alternative to 'find'.
shimakaze_softshimakaze_soft

依存関係を追加する

アプリケーションに依存関係を追加します。

Rustのパッケージレジストリであるcrates.io上で、あらゆる種類のライブラリを見つけることができる。

Rustではパッケージのことをよくクレートと呼びます。

このプロジェクトでは、ferris-saysと呼ばれるクレートを使用します。

Cargo.tomlファイルにこの情報(クレートページから取得)を追加します。

Cargo.toml
[dependencies]
ferris-says = "0.2"

cargo build

上記のコマンドでCargoが依存関係をインストールします。

このコマンドの実行によってCargo.lockという新しいファイルが作成されていることがわかる。

このファイルは私達がローカルで使っている依存関係の厳密なバージョンを記録しています。

この依存関係を使うためにmain.rsを開いて以下の行を追加します。

main.rs
use ferris_says::say;

この行はferris-saysクレートがエクスポートしたsay関数を使えることを示しています。

shimakaze_softshimakaze_soft

Rustアプリケーションの初歩

新しい依存関係を持った小さなアプリケーションを書いてみます。
main.rsの中に、次のコードを追加します。

main.rs
use ferris_says::say; // from the previous step
use std::io::{stdout, BufWriter};

fn main() {
    let stdout = stdout();
    let message = String::from("Hello fellow Rustaceans!");
    let width = message.chars().count();

    let mut writer = BufWriter::new(stdout.lock());
    say(message.as_bytes(), width, &mut writer).unwrap();
}

以下のコマンドでアプリケーションを実行する。

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hello-rust`
 __________________________
< Hello fellow Rustaceans! >
 --------------------------
        \
         \
            _~^~^~_
        \) /  o o  \ (/
          '_   -   _'
          / '-----' \
shimakaze_softshimakaze_soft

Rustの変数

Rustの変数は全てデフォルトではimmutable(不変)であるため、値の変更はできない。

# 以下はコンパイルエラーになる
let x = 100;
x = 200;

Rustでは、値を変更してはいけないのに変更できてしまう、それがバグのもとになると考えています。

もし、後から変数を変更したい場合は、mutをつけます。こうすることで、変数はmutable型(可変)になり、後に変数の値を変更することが可能です。

# 以下はコンパイルエラーにならない
let mut x = 100;
println!("{}", x);      // 100
x = 200;
println!("{}", x);      // 200

データ型

Rustにはデータ型というものがあり、大きく分けて「スカラー型」と「複合型」があります。

スカラー型

  • 整数型
  • 浮動小数点型
  • 論理値型
  • 文字型

整数型

整数型は、小数点がない数値を表すデータ型です。
以下の通り、大きさと符号の有無に応じた6つの整数型があります。

大きさ 符号付き 符号なし
8bit i8 u8
16bit i16 u16
32bit i32 u32
64bit i64 u64
128bit i128 u128
アーキテクチャ依存 isize usize

符号付き整数はi(integer)で始まり、符号なし整数はu(unsigned)で始まる。
大きさをbit数で続けます。

アーキテクチャ依存はisizeusizeとなります。

8bitから始まって128bitまでの整数を表すことができます。

また基準型というものがスカラー型にはあり、整数型ではi32が基準型になります。

浮動小数点型

小数値を表すデータ型です。
f32f64があり、それぞれ32bit、64bitのサイズを持ち、基準型はf64です。

f32は単精度浮動小数点数、f64は倍精度浮動小数点数を表現する。

論理値型

論理値型は、真偽を表すデータ型です。
データ型はboolで、値はtrueとfalseしかとらない。

文字型

文字型は、文字を表すデータ型。

データ型はcharです。C/C++のcharも文字型ですが、これはASCIIコード(7bit)を表すのに対して、RustのcharはUnicodeを表す。

そのため日本語などの文字も表現できる。


基準型

整数型と浮動小数点型に基準型というのが出てきた。

基準型というのは、型注釈のない変数宣言などで、優先して選択されるデータ型のことです。

例えば、以下のように整数型の変数xを宣言したいとき、i32すなわち32bitの符号付き整数として宣言されたと見なされる。

浮動小数点型も同様で、以下ではf64が選択される。

let x = 10;     // i32
let y = 3.14;   // f64

型注釈

Rustでは、データ型を型注釈という形で指定します。上記の変数宣言を型注釈付きで示すと以下のようになる。

let x: i32 = 10;
let y: f64 = 3.14;

変数名の後にコロン(:)を続けて、その後にデータ型を記述する。

複合型

複合型とは、複数のスカラー型の値をまとめて扱うためのデータ型。

複合型には、以下の2つがある。

  • タプル(tuple)
  • 配列(array)

タプル型

タプル型は、複数のスカラー型の値をまとめて扱えるデータ型ですが、スカラー型がそれぞれ異なっていても扱うことができる。Pythonでも似たようなものがあります。

C/C++における構造体のように見えるかも知れませんが、それぞれの値に名前はない。

let t = (2, 3.14, 0);
let (a, b, c) = t;
println!("a={}, b={}, c={}", a, b, c);  // a=2, b=3.14, c=0

let x = t.0;
let y = t.1;
let z = t.2;
println!("x={}, y={}, z={}", x, y, z);  // x=2, y=3.14, z=0

まず、タプル型の変数tを「2」「3.14」「0」という3つの値を持つように宣言している。
型注釈がないので、i32、f64、i32がデータ型として選択される。

変数は1個なのに値が3つあります。これは他の変数群の初期化に用いたり、インデックスを用いて個別に取り出したりできる。
変数a, b, cにはtの値である2, 3.14, 0が入る。

変数x, y, zについても同様です。

個別に取り出す場合、インデックスは0から始まることに注意が必要。

これは、C/C++/Javaなどにおけるインデックスの考え方と同じであり、またインデックスは後述する配列と同様のチェックが行われて、範囲外のインデックスが指定された場合にエラーが発生する。

配列

配列型には、同じデータ型の値を複数持たせることができる。

aは配列型で、i32がデータ型として選択されます。
要素数は5個になります。参照も同様で、大かっこ([])にインデックスを入れて指定する。

let a = [1, 2, 3, 4, 5];
let x = a[0];
let y = a[1];
let z = a[2];
println!("x={}, y={}, z={}", x, y, z);  // x=1, y=2, z=3

一度宣言した配列の要素数を変更することはできない。
この欠点を克服する手段として、コレクションライブラリが用意されています。

代表的なのはベクターです。