📖

今更Rust触ってみた

2023/12/09に公開

概要

そういえばRustを触ったことがなかったので触ってみた。
触ってみた記録を残す。
rustど素人の記事なので同じく始めての方の目線と同じ観点で書けるのでは。

https://www.rust-lang.org/

前提

経緯

触ってみたいと思った理由はただ一つ。流行ってるのに触ってなかったから。
コードに触れる者をこのままでは語れないと思って一通り触ってみようと思った次第。

Rustとは

思想として、サイズが小さく、速く動作するプログラムをメモリ・バグを起こすことなくかけるようにすることを目指し、「生き延びるために過剰な改良を重ねたサビ菌」から命名したプログラミング言語

Welcome to The Rust Programming Language, an introductory book about Rust. The Rust programming language helps you write faster, more reliable software. High-level ergonomics and low-level control are often at odds in programming language design; Rust challenges that conflict. Through balancing powerful technical capacity and a great developer experience, Rust gives you the option to control low-level details (such as memory usage) without all the hassle traditionally associated with such control.

https://doc.rust-lang.org/book/ch00-00-introduction.html

作成のきっかけが、家のエレベーターがメモリの使い方によるクラッシュでよく止まるから、速く動作して、メモリのバグ生じないようなプログラミング言語作成しようっていう発想になるのがなかなかクレイジーですね。

https://www.technologyreview.jp/s/306125/how-rust-went-from-a-side-project-to-the-worlds-most-loved-programming-language/

言語仕様的には静的型付け、式ベースの言語であり、手続型・関数型プログラミングの両方を実装できるようになっている。

https://zenn.dev/mebiusbox/books/22d4c1ed9b0003/viewer/6d5875

まずは遊ぶ

環境構築まずはやろう!ってなって環境構築に時間がかかって自分の興味は何処へ...
って感じになるのでまずはTour of Rustで動かしてみる。

https://tourofrust.com/

あらかわいい

開いたら既にhello worldが打てる状態。
上記のzennの記事読みながら気になったのがobjectに関して。

fn main() {
    if 1 == {1} {
        print!("success of object test!");
    } else {
        print!("failed of object test....");
    }
}

rustでrunしたら等しいとみなされるが、

success of object test!
# Online Python Playground
if 1 == {1}:
    print("success of object test")
else:
    print("failed of object test...")

pythonでrunしたら等しくないとみなされる。

failed of object test...

これはrustが数値や関数や参照など、型の実態を全てオブジェクトと定義しているので、式が返す値もオブジェクトになるから、
ブロック{}で囲まれた{1}という値も、1という値も同じ数値オブジェクトとして判定されるから。
おもろい。

構造体に関しては一つ一つのフィールドをkey:valueという形で記載する。
ぱっと見golangとかと書き方は似ているが、rustには所有権が関わってきます。

所有権に関しては、実行中に管理する必要のあるメモリを管理する機能であり、
インスタンスを作成した際に、メモリリソースを作成するための束縛、
もし一時的に所有権を使ってオブジェクトを受渡したければ参照を用いることで、
ヒープ状の重複するデータを最小化し、メモリ不足を防いでいる。

fn main() {
    // 変数束縛: `s`はString型の値を束縛している
    let s = String::from("hello");

    // 不変参照: `s_ref`は`s`の不変の参照
    let s_immutable = &s;

    // `s`の値を出力(所有権は移動しない)
    println!("s: {}", s);

    // `s_immutable`を通じて`s`の値を出力(所有権は移動しない)
    println!("s_immutable: {}", s_immutable);

    // 可変参照: `s`の可変の参照を作成
    let mut s = s;
    let s_mut_refference = &mut s;

    // `s_mut_refference`を通じて`s`の値を変更
    s_mut_refference.push_str(", world");

    // 変更された`s`の値を出力
    println!("s: {}", s);
}
s: hello
s_immutable: hello
s: hello, world

クロシージャとかもあるが、やりつつこの記事に疑問が生じたら都度調べて追記していく。

パッケージ管理して単体テストまでやる

rustは以下のページからダウンロードページに飛んでそのままインストールを行うと、
勝手に単体テストを行うためのcargoも追加してくれる。

-- install
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
rustc --version
cargo --version

-- package init
cargo init

-- build command
cargo build

-- run
cargo run

https://qiita.com/yoshii0110/items/6d70323f01fefcf09682

どうやらrustは実装コードとテストコードを同じファイル(src/*/rs)に記述するらしい。
各モジュールをtestの時だけテストコードがコンパイル対象になるから、製品開発においてテストコードも同じファイルに入れておいても問題はない。

fn main() {
    println!("{}", hello_world());
}

fn hello_world() -> &'static str {
    "Hello, world!"
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_hello_world() {
        assert_eq!(hello_world(), "Hllo, world!");
    }
}

Compiling rust_train v0.1.0 (/Users/XXXXX/rust_train)
    Finished test [unoptimized + debuginfo] target(s) in 0.82s
     Running unittests src/lib.rs (target/debug/deps/rust_train-e948cd7a08e56edb)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/main.rs (target/debug/deps/rust_train-eaefa4e8127dc227)

running 1 test
test tests::test_hello_world ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests rust_train

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

失敗させたら以下の感じ

cargo test
    Finished test [unoptimized + debuginfo] target(s) in 0.03s
     Running unittests src/lib.rs (rust_train-e948cd7a08e56edb)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/main.rs (target/debug/deps/rust_train-eaefa4e8127dc227)

running 1 test
test tests::test_hello_world ... FAILED

failures:

---- tests::test_hello_world stdout ----
thread 'tests::test_hello_world' panicked at src/main.rs:16:9:
assertion `left == right` failed
  left: "Hello, world!"
 right: "Hllo, world!"
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::test_hello_world

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

結論

ただの触ってみた記事になっちゃったので実際に開発した際に細かい処理で整理すべきこととかあったらこの記事に記載したい。

参考文献

https://www.rust-lang.org/

https://www.technologyreview.jp/s/306125/how-rust-went-from-a-side-project-to-the-worlds-most-loved-programming-language/

https://zenn.dev/mebiusbox/books/22d4c1ed9b0003/viewer/6d5875

https://tourofrust.com/

Discussion