Open10

The Rust Programming Language をやってみる

ふみふみふみふみ

数あてゲームまでは終わった!!
本当にやっただけなので、知らなかったところはアウトプットしておきます。

Cargoって?

3行で話すと

  • Rustのビルドシステム兼パッケージマネージャ
  • どのOSでもコマンドが同じ(ex: cargo ~~
  • cargo doc --open をすると、ローカルで使用中のクレートのドキュメントをまとめたものを生成してくれる

参考

https://doc.rust-jp.rs/book-ja/ch01-03-hello-cargo.html

CargoはRustのビルドシステム兼パッケージマネージャです。 ほとんどのRustaceanはこのツールを使ってRustプロジェクトを管理しています。

argo checkは実行ファイルを生成するステップを省くことができるので、多くの場合、cargo buildよりもずっと高速です。 もし、あなたがコードを書きながら継続的にチェックするのなら、cargo checkを使えば、そのプロセスを高速化できます! そのため多くのRustaceanはプログラムを書きながら定期的にcargo checkを実行し、コンパイルできるか確かめます。 そして、実行ファイルを使う準備ができたときにcargo buildを走らせるのです。

Cargoを使用するもう一つの利点は、どのOSで作業していてもコマンドが同じであることです。 そのため、これ以降はLinuxやmacOS向けの手順と、Windows向けの手順を分けて説明することはありません

これもRustを使ってて楽しいポイントの一つかも。

https://doc.rust-jp.rs/book-ja/ch02-00-guessing-game-tutorial.html

cargo runコマンドを使って、この「Hello, world!」プログラムのコンパイルと実行を一気に行いましょう。

このゲーム(の開発)では各イテレーションを素早くテストしてから、次のイテレーションに移ります。 runコマンドは、今回のようにプロジェクトのイテレーションを素早く回したいときに便利です。

イテレーションとは開発工程の「一回のサイクル」のことで、サイクルには、設計、実装、テスト、改善(リリース後の振り返り)が含まれます。 アジャイル開発ではイテレーションを数週間の短いスパンで一通り回し、それを繰り返すことで開発を進めていきます。

この章では「実装」→「テスト」のごく短いサイクルを繰り返すことで、プログラムに少しずつ機能を追加していきます。

https://doc.rust-jp.rs/book-ja/ch02-00-guessing-game-tutorial.html

Cargoのもう一つの素晴らしい機能は、cargo doc --openコマンドを走らせると、すべての依存クレートが提供するドキュメントをローカルでビルドして、ブラウザで開いてくれることです。 たとえばrandクレートの他の機能に興味があるなら、cargo doc --openコマンドを実行して、左側のサイドバーにあるrandをクリックしてください。

実際に生成して閲覧してる図↓
すごい〜〜!

自分が作っているプロジェクトについても一応載せてくれる。

The bookで言及されていたrand

Python使ってたところから見たRustの好きなとこ

エラーがとにかくわかりやすい

typoまで検知してhelpで出してくれる

https://x.com/2323_code/status/1822624447427482080

前からあるのかもしれないけど、Rustの好きなとこ、こういうとこです...ガッツリtypoしてるけど、それに対して「多分これじゃない?」って提示してくれるとこ...
(他の言語でもあるのかもしれないけど)大変好きです...嬉しい。。。

ふみふみふみふみ

式と文の違い

  • 式:
    • セミコロンが終わりにない。
  • 文:
    • セミコロンが最後につく。
    • 値を返さない。

https://doc.rust-jp.rs/book-ja/ch03-03-how-functions-work.html

式は終端にセミコロンを含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。そして、文は値を返しません。 次に関数の戻り値や式を見ていく際にこのことを肝に銘じておいてください。

ふみふみふみふみ

https://doc.rust-jp.rs/book-ja/ch04-02-references-and-borrowing.html
参照もまだちょっと難しい感じ。ふんわり知っておこう。

&による参照の逆は、参照外しであり、参照外し演算子の*で達成できます。

&s1という記法により、s1の値を参照する参照を生成することができますが、これを所有することはありません。 所有してないということは、指している値は、参照がスコープを抜けてもドロップされないということです。

参照について議論したことを再確認しましょう:

  • 任意のタイミングで、一つの可変参照か不変な参照いくつでものどちらかを行える。
  • 参照は常に有効でなければならない
ふみふみふみふみ

https://doc.rust-jp.rs/book-ja/ch04-01-what-is-ownership.html#スタックのみのデータ-コピー

整数のようなコンパイル時に既知のサイズを持つ型は、スタック上にすっぽり保持されるので、 実際の値をコピーするのも高速だからです。これは、変数yを生成した後にもxを無効化したくなる理由がないことを意味します。 換言すると、ここでは、shallow copyとdeep copyの違いがないことになり、 cloneメソッドを呼び出しても、一般的なshallow copy以上のことをしなくなり、 そのまま放置しておけるということです。

どの型がCopyなのでしょうか?ある型について、ドキュメントをチェックすればいいのですが、 一般規則として、単純なスカラー値の集合は何でもCopyであり、メモリ確保が必要だったり、 何らかの形態のリソースだったりするものはCopyではありません。

  • あらゆる整数型。u32など。
  • 論理値型であるbool。trueとfalseという値がある。
  • あらゆる浮動小数点型、f64など。
  • 文字型であるchar。
  • タプル。ただ、Copyの型だけを含む場合。例えば、(i32, i32)はCopyだが、 (i32, String)は違う。

なんとなくはわかったけど、&strStringの場合で挙動が異なるのはなぜかわかっていないかも ...

fn main() {
    let s1 = String::from("hello"); // String
    let s2 = s1; // String

    let x = "hello"; //&str
    let y = x; // &str

    println!("x={}, y={}", x, y);
    // OK

    println!("s1={}, x={}, y={}", s1, x, y);
    // s1込みだとerror[E0382]: borrow of moved value: `s1` となる。
}

わかっていること

  • String::from()で呼び出して変数の値を定義する場合(s1, s2)と、そのままダブルクォーテーションで囲むだけで変数の値を定義する場合(x, y)だと挙動がかわる

分からないこと

  • String&strの違い、挙動の制限の違い
ふみふみふみふみ

https://doc.rust-jp.rs/book-ja/ch04-01-what-is-ownership.html#所有権と関数

所有権と関数のところで、String::from() で変数を定義した場合と、
文字列そのまま定義した場合で型が違うし挙動も違う...👀

それぞれの型のドキュメントみた方が良いかも、、、

fn main() {
    let s = "hello";
    // let s = String::from("hello");
    println!("{}", s);
    takes_ownership(s);
    println!("{}", s);

    let x = 5;
    println!("{}", x);
    makes_copy(x);
    println!("{}", x);
}

fn takes_ownership(some_string: &str) {
    println!("{}", some_string);
}

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
}

結果。

hello
hello
hello
5
5
5
ふみふみふみふみ

https://doc.rust-jp.rs/book-ja/ch04-02-references-and-borrowing.html

参照

ここの関数呼び出しについて、もっと詳しく見てみましょう:

let s1 = String::from("hello");
let len = calculate_length(&s1);

この&s1という記法により、s1の値を参照する参照を生成することができますが、これを所有することはありません。 所有してないということは、指している値は、参照がスコープを抜けてもドロップされないということです。

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);

    println!("The lentgh '{}' is {}.", s1, len); // 結果:The lentgh 'hello' is 5.
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

借用とは:

関数の引数に参照を取ることを借用と呼びます。

fn calculate_length(s: &String) のような場合は借用、ってことかな

参照について議論したことを再確認しましょう:

  • 任意のタイミングで、一つの可変参照か不変な参照いくつでものどちらかを行える。
  • 参照は常に有効でなければならない。