Rust 学習記録(1)

  • 以下のページで学習を開始
  • Rust は rustup と rust-analyzer を homebrew でインストール
  • bootstrap で .cargo フォルダがないことを確認の上で rustup-init を実行
  • vscode の Rust 機能拡張を追加
"[rust]": { "editor.formatOnSave": true, },
  • 単一ファイルの記述
fn main() { println!("Hello, world!"); }
  • rustc でコンパイルして実行。これは cc と変わらない
rustc main.rs ./main
  • でも実際のプロジェクトはこんな簡単ではないので、cargo を使う。ビルドツールであり、環境依存マネージャーでもあるとのこと。cargo new でプロジェクトを作成
cargo new hello-cargo
  • 設定などは Cargo.toml で記述。toml ファイルは vim 以来か。cargo run でプログラム実行
cargo run
 
Rust プログラム構造の概要 - Learn
次のコードを調べて、単純な Rust プログラムがどのように構造化されているかを確認しましょう。 fn main() { println!("Hello, world!"); } 最初の Rust プログラムでは、 main という名前の " 関数" が定義されています。 関数は、特定のタスクを実行するコードのブロックです。 プログラム内のコードをタスクに基づいてブロックに分割します。 この分割により、コードの理解と保守が容易になります。 タスクの関数を定義したら、そのタスクを実行する必要があるときに関数を呼び出すことができます。 すべての Rust プログラムには、 main という名前の関数が 1 つ 必要です。 main 関数内のコードは、常に、Rust プログラムで最初に実行されるコードです。 main 関数内または他の関数内から他の関数を呼び出すことができます。 Rust 内で関数を宣言するには、 fn キーワードを使用します。 関数名の後に、関数が入力として受け取るパラメーターまたは " 引数" の数をコンパイラに指示します。 引数のセットがかっこ () 内に一覧表示されます。 かっこが空の場合、関数には入力引数がありません。 main 関数は、入力引数を持たない関数の例です。 fn main()
Rust プログラム構造の概要 - LearnRust プログラム構造の概要 - Learn
  • 関数について。関数は fn で記述。Ruby の def と同じ感じ。行は ; で終わるが、終わらない時は次の行を 4 インデントする。このあたりはフォーマッタがなんとかしてくれると信じる
fn main() { // The function declaration is not indented // First step in function body // Substep: execute before First step can be complete // Second step in function body // Substep A: execute before Second step can be complete // Substep B: execute before Second step can be complete // Sub-substep 1: execute before Substep B can be complete // Third step in function body, and so on... }
  • println! はマクロ。{} は C 言語の %s みたいな感じ。数字などが渡されても文字列変換メソッドが入るので、型を区別しなくていいということ。
println!("The first letter of the English alphabet is {} and the last letter is {}.", 'A', 'Z');
  • {} を書きたい時にはどうするんだろう。と思って色々やってみたが、これでいいのかな。\{\}ではなかった。
fn main() { println!("{}{{}}", 1); }
変数を作成して使用します - Learn
開発者は、データを操作するコンピューター プログラムを記述します。 データの収集、分析、保存、処理、共有、報告が行われます。 " 変数" を使用して、コード内で後で参照できる名前付き参照にデータを格納します。 Rust では、変数はキーワード let を使用して宣言されます。 各変数には一意の名前が付いています。 変数が宣言されている場合は、値にバインドできます。また、後でプログラム内で値をバインドすることもできます。 次のコードでは、 a_number という名前の変数を宣言しています。 let a_number; a_number 変数はまだ値にバインドされていません。 このステートメントを変更して、値を変数にバインドできます。 let a_number = 10; 注意 キーワード: 他のプログラミング言語と同様に、 fn や let などの特定の " キーワード" は、Rust でのみ使用するために予約されています。 キーワードを関数または変数の名前として使用することはできません。 別の例を見てみましょう。 次のコードでは、2 つの変数が宣言されています。 最初の変数が宣言され、数値にバインドされます。 2 番目の変数は宣言されていますが、値にバインドされていません。 プログラムの後の部分で、2 番目の変数の値が単語にバインドされています。 コードでは、変数の値を表示する println!
変数を作成して使用します - Learn変数を作成して使用します - Learn
  • 変数について。変数は let で設定。変数は不変(immutable)なので再代入は不可。
let a_number; let a_word = "Ten"; a_number = 10; a_number = 15; // エラー
  • 可変(mutable)にしたければ mut を付ける。デフォルトではないということは滅多には使わない感じか。後で出てくる構造体の一部だけ変更するような時に使うくらいではないかとのこと。
let mut a_number = 10; a_number = 15;
  • 変数のシャドウ処理。mut だといつでも変更可能になってしまうので、シャドウ処理で同じ変数名を付けることができる。これだとあまり意味がないが、スコープが変わると意味があるかも。
let shadow_num = 5; let shadow_num = shadow_num + 5;
  • 型推論は自動で行われるが、自分で型を指定することもできる。 u32 は符号なし32ビット整数
let number: u32 = 14;
  • 型を指定しているのに違うものを入れるとコンパイル時点でエラーになる。静的にエラーになるのは嬉しい。
let number: u32 = "14"; // コンパイルエラー
  • 整数型
    • i8, i16, i32, i64, isize が符号あり
    • u8, u16, u32, u64, usize が符号なし
    • 型推論できない時は i32
  • 浮動小数点型
    • f32 と f64。デフォルトは f64
    • let number_64 = 4.0; let number_32: f32 = 5.0;
  • ブール値
    • true または false。条件式を実行すると true か false が生成される
    • let is_bigger = 1 > 4;
  • 文字
    • '' で括ると文字
    • 内部は 21ビットの Unicode code (UTF-8 ではない)
 
  • 文字列1 (str 型)
    • "" で括ると文字列。文字列リテラルなどで長さが既知
    • 参照する場合には &str になる。& は参照を示す
  • 文字列2 (String 型)
    • 長さがわかっていない場合。作り方は後で出てくると思う
  • タプル
    • 表記は Swift と同じ。
    • タプルの長さは固定。作成時に決定
    • 中身はなんでも良い。下の例では文字列、数値、ブーリアン値が入っている
    • let tuple_e = ('e', 5i32, true);
If/else 条件式を使用する - Learn
プログラミングの重要な部分は、データに基づいて意思決定を行うことです。 このユニットでは、条件をテストしてプログラムのアクションを制御する方法について説明します。 if および else キーワードを使用して、コード内に " 条件分岐" を作成できます。 多くのプログラミング言語によってこの機能が提供されており、同様の構文が使用されます。 if および else キーワードは、値をテストし、テスト結果に基づいてアクションを実行するために式と共に使用されます。 すべての条件式の結果は、ブール値の true または false になります。 2 つの数値が等しいかどうかをテストし、テスト結果に基づいてメッセージを出力する例を次に示します。 if 1 == 2 { println!("True, the numbers are equal."); // } else { println!("False, the numbers are not equal."); } 前の例では、 if の条件は式 1 == 2 で、これは false の値を持つブール型に評価されます。 他のほとんどの言語とは異なり、Rust の if ブロックは式としても機能できます。 条件分岐内のすべての実行ブロックでは、コードをコンパイルするために同じ型を返す必要があります。 let formal = true; let greeting = if formal { // if used here as an expression "Good day to you."
If/else 条件式を使用する - LearnIf/else 条件式を使用する - Learn
  • if は条件式を記述。Ruby のように式には () はいらない
if 1 == 2 { println!("True, the numbers are equal."); // } else { println!("False, the numbers are not equal."); }
  • Ruby と同じく if 自体が値を返すので、C の三項演算子のように使える。let の文になるので最後にセミコロンが必要。Ruby だと「;」がいらないので気にならないが、Rust だと「};」の形になることに注意。
let formal = true; let greeting = if formal { // if used here as an expression "Good day to you." // return a String } else { "Hey!" // return a String };
  • 複数の条件分岐は else if となる。
let num = 500 // num variable can be set at some point in the program let out_of_range: bool; if num < 0 { out_of_range = true; } else if num == 0 { out_of_range = true; } else if num > 512 { out_of_range = true; } else { out_of_range = false; }
構造体と列挙型について学ぶ - Learn
構造体は、他の型で構成される型です。 構造体の要素は " フィールド" と呼ばれます。 タプルと同様に、構造体のフィールドは異なるデータ型を持つことができます。 構造体型の大きな利点は、各フィールドに名前を指定して値の意味を明確にできることです。 Rust プログラムで構造体を操作するには、まず構造体を名前で定義し、各フィールドのデータ型を指定します。 次に、別の名前を使用して構造体の " インスタンス" を作成します。 インスタンスを宣言する場合は、フィールドに特定の値を指定します。 Rust では、従来の構造体、タプル構造体、ユニット構造体という 3 つの構造体型がサポートされています。 これらの構造体型により、データのグループ化や操作を行うさまざまな方法がサポートされます。 は最もよく使われています。 構造体内の各フィールドには、名前とデータ型があります。 従来の構造体を定義した後は、構文 . を使用して構造体内のフィールドにアクセスできます。 タプル構造体 は従来の構造体に似ていますが、フィールドには名前がありません。 タプル構造体内のフィールドにアクセスするには、タプルのインデックス付けの場合と同じ構文 ( .
構造体と列挙型について学ぶ - Learn構造体と列挙型について学ぶ - Learn
  • 構造体の種類は3種類
    • 従来の構造体: key-value 形式。Ruby の Hash に近いイメージだが、定義した時以上にキーは増えない
    • タプル構造体: 中身はタプルでキーはない。要素の並びが固定化されたタプルの雛形
    • ユニット構造体: ここでは説明がないので、後で出てきた時に確認
  • 構造体の命名規則
    • Ruby の Class 名のように大文字で始める
  • 従来の構造体
    • 定義方法(従来の構造体)
      • key-value をあらかじめ宣言する。要素はフィールドと呼ぶとのこと
      • 他の二つと違って、最後に「;」を書かないとのこと。これは間違えそうなので注意。
      // Classic struct with named fields struct Student { name: String, level: u8, pass: bool }
    • 構造体の作成(従来の構造体)
      • 作り方は構造体名を記述後に、Ruby の Hash と同じ形式で記載する。
      • name は String なので、"" の str 型は入れられない。String::from で str 型から String 型に変換するようだ
      let user_1 = Student { name: String::from("Constance Sharma"), remote: true, level: 2 }; let user_2 = Student { name: String::from("Dyson Tan"), level: 5, remote: false };
    • 構造体の利用方法(従来の構造体)
      • 構造体のフィールドへのアクセスは C 言語と同じく、.フィールド名と書けばよい
      println!("{}, level {}. Remote: {}. Grades: {}", user_1.name, user_1.level, user_1.remote); println!("{}, level {}. Remote: {}. Grades: {}", user_2.name, user_2.level, user_2.remote);
  • タプル構造体
    • 定義方法(タプル構造体)
      • タプルには名前がないので、定義時には型だけを並べる
      • 通常の構造体と異なり、「;」は必要
      • // Tuple struct with data types only struct Grades(char, char, char, char, f32);
    • 構造体の作成(タプル構造体)
      • タプル構造体は構造体名の後にタプルの生成が入る。
      • 通常のタプルとの違いは型の並びが固定化されていること
      • // Instantiate tuple structs, pass values in same order as types defined let mark_1 = Grades('A', 'A', 'B', 'A', 3.75); let mark_2 = Grades('B', 'A', 'A', 'C', 3.25);
    • 構造体の利用方法(タプル構造体)
      • タプルの要素には.1, .2 のように要素番号を記述する。
      • println!("{}, {}, {}. Average: {}", mark_1.0, mark_1.1, mark_1.2, mark_1.3, mark_1.4); println!("{}, {}, {}. Average: {}", mark_2.0, mark_2.1, mark_2.2, mark_2.3, mark_2.4);
  • 列挙型
    • 列挙型について
      • C 言語の列挙型とは全く意味が違う。
      • elm のカスタム型と同じで、複数のバリアントを同じ枠にハメるための仕組み
      • 静的型付けが必要なため、多様性が必要な入力などを取りまとめるために利用
    • 列挙型の定義
      • 以下の例では WebEvent という列挙型を定義している
      • ここでは、 WELoad, WEKeys , WEClick という三つのバリアントをまとめている
      • WELoad はまだ説明されていないユニット構造体、 WEKeys はタプル構造体、 WEClick は従来の構造体。それぞれは匿名構造体
      • 列挙型を受け付ける場合には、全てに対して処理を受け付けるようにしなければならない
      • enum WebEvent { // An enum variant can be like a unit struct without fields or data types WELoad, // An enum variant can be like a tuple struct with data types but no named fields WEKeys(String, char), // An enum variant can be like a classic struct with named fields and their data types WEClick { x: i64, y: i64 } }
    • 構造体による列挙型定義
      • 匿名構造体で処理するのは面倒なので、定義された構造体を使って列挙型を作る方がよいらしい
      • // Define a tuple struct struct KeyPress(String, char); // Define a classic struct struct MouseClick { x: i64, y: i64 } // Redefine the enum variants to use the data from the new structs // Update the page Load variant to have the boolean type enum WebEvent { WELoad(bool), WEClick(MouseClick), WEKeys(KeyPress) }
    • 列挙型のインスタンス化
      • 単純なバリアント。boolean の引数だけを一つもつ場合
      • let we_load = WebEvent::WELoad(true);
      • 通常の構造体を引数に持つバリアント。x, y = (100, 250) を持つ MouseClick 構造体を受け付ける
      • // Instantiate a MouseClick struct and bind the coordinate values let click = MouseClick { x: 100, y: 250 }; // Set the WEClick variant to use the data in the click struct let we_click = WebEvent::WEClick(click);
      • タプル構造体を引数に持つバリアント。String 型と char のタプルを持つ KeyPress 構造体を受け付ける
      • // Instantiate a KeyPress tuple and bind the key values let keys = KeyPress(String::from("Ctrl+"), 'N'); // Set the WEKeys variant to use the data in the keys tuple let we_key = WebEvent::WEKeys(keys);
    • 提示されているサンプルプログラムの表示部分
      • {:#?}を使っている。ただしこのままでは動作しない
      • println!("\nWebEvent enum structure: \n\n {:#?} \n\n {:#?} \n\n {:#?}", we_load, we_click, we_key);
      • {:#?}を使うためには、その構造体や列挙型の前に #[derive(Debug)] を付ける必要がある。
      • // Define a tuple struct #[derive(Debug)] struct KeyPress(String, char); // Define a classic struct #[derive(Debug)] struct MouseClick { x: i64, y: i64, } // Redefine the enum variants to use the data from the new structs // Update the page Load variant to have the boolean type #[derive(Debug)] enum WebEvent { WELoad(bool), WEClick(MouseClick), WEKeys(KeyPress), }
Rust で関数を操作する - Learn
関数は、Rust 内でコードを実行する主要な方法です。 この言語で、最も重要な関数の 1 つは既に見た main 関数です。 このユニットでは、関数を定義して使用する方法を詳細に説明します。 前に説明したいくつかの関数の基本を確認しましょう。 Rust での関数定義は、 fn キーワードで始まります。 関数名の後に、関数の入力引数を、かっこ内のデータ型のコンマ区切りリストとして指定します。 中かっこは、関数本体の開始と終了の位置をコンパイラに伝えます。 fn main() { println!("Hello, world!"); goodbye(); } fn goodbye() { println!("Goodbye!"); } 関数を呼び出すには、その名前をかっこ内の入力引数と共に使用します。 関数に入力引数が存在しない場合は、かっこを空のままにします。 この例では、 main と goodbye の両方の関数に入力引数がありません。 main 関数の後に goodbye 関数が定義されていることにお気付きかと思います。 goodbye 関数は、 main を定義する前に定義しました。 Rust では、関数がファイル内のどこかに定義されている限り、ファイル内のどこに定義されているかは留意されません。 関数に入力引数がある場合は、各引数に名前を付け、関数宣言の最初にデータ型を指定します。 引数には変数のように名前が付けられているので、関数本体内で引数にアクセスできます。 ある数値が別の数値で割り切れるか (剰余がないか) どうかをチェックするための関数を宣言してみましょう。 fn is_divisible_by(dividend: u32, divisor: u32) { // If the divisor is zero, stop execution if divisor == 0 { println!("\nError!
Rust で関数を操作する - LearnRust で関数を操作する - Learn
  • 関数の基本
    • Rust の関数は fn で始まる。Ruby の def と同じイメージで。ただし、関数のスコープは {}。引数なしでも () は必要の様子。
      • fn main() { println!("Hello, world!"); goodbye(); } fn goodbye() { println!("Goodbye!"); }
  • 関数の入力引数
    • 引数は変数名の後ろに型を書く。Swift と同じ形だが、Swift や Objective-C のようにラベルはつけない。Swift の _ 付きのような感じ。今は IDE やエディタのサポートがあるので、ラベルがなくてもミスらないということか。
    • fn is_divisible_by(dividend: u32, divisor: u32) { // If the divisor is zero, stop execution if divisor == 0 { println!("\nError! Division by zero is not allowed."); } else if dividend % divisor > 0 { println!("\n{} % {} has a remainder of {}.", dividend, divisor, (dividend % divisor)); } else { println!("\n{} % {} has no remainder.", dividend, divisor); } } fn main() { is_divisible_by(12, 4); is_divisible_by(13, 5); is_divisible_by(14, 0); }
  • 関数の戻り値
    • 関数の戻り値は Swift と同じ形で関数名の後ろに -> で型を記述する。
    • 値を途中で返すときには、return 文を使うことができる。これはステートメントなので「;」が必要
    • Ruby と同じで最後に評価した式も返り値にになる。これはステートメントでないので、「;」をつけてはいけない。
    • デフォルトは最後に式を書く形だと思われる。
    • fn is_zero(input: u8) -> bool { if input == 0 { return true; } false } fn main() { if is_zero(0) { println!("The value is zero."); } }
  • 演習の解説は省略
    • 演習結果はこんな感じになりました。PartialEq だけがまだ説明がないですね。
    • // Declare Car struct to describe vehicle with four named fields struct Car { color: String, transmission: Transmission, convertible: bool, mileage: u32, } #[derive(PartialEq, Debug)] // Declare enum for Car transmission type // TO DO: Fix enum definition so code compiles enum Transmission { Manual, SemiAuto, Automatic, } // Build a "Car" by using values from the input arguments // - Color of car (String) // - Transmission type (enum value) // - Convertible (boolean, true if car is a convertible) fn car_factory(color: String, transmission: Transmission, convertible: bool) -> Car { // TO DO: Complete "car" declaration to be an instance of a "Car" struct // Use the values of the input arguments // All new cars always have zero mileage Car { color: color, transmission: transmission, convertible: convertible, mileage: 0, } } fn main() { // We have orders for three new cars! // We'll declare a mutable car variable and reuse it for all the cars let mut car = car_factory(String::from("Red"), Transmission::Manual, false); println!( "Car 1 = {}, {:?} transmission, convertible: {}, mileage: {}", car.color, car.transmission, car.convertible, car.mileage ); car = car_factory(String::from("Silver"), Transmission::Automatic, true); println!( "Car 2 = {}, {:?} transmission, convertible: {}, mileage: {}", car.color, car.transmission, car.convertible, car.mileage ); car = car_factory(String::from("Yellow"), Transmission::SemiAuto, false); println!( "Car 3 = {}, {:?} transmission, convertible: {}, mileage: {}", car.color, car.transmission, car.convertible, car.mileage ); }
  • 配列
    • 配列の定義は2種類
      • コンマ区切りで要素を並べる
      • 初期値と配列の長さで指定
      • // Declare array, initialize all values, compiler infers length = 7 let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; // Declare array, first value = "0", length = 5 let bytes = [0; 5];
    • 配列は[T; size]という形で内部に保存される
      • 配列の要素の方は T で固定。Ruby などと違ってどんな型が入ってもいいわけでない
      • 配列のサイズも size で固定。可変長ではない
    • 配列のインデックス
      • 配列の要素は他の言語と同様に 0 から始まる。特に問題はなし
      • 範囲外のアクセスについて、コンパイラが判断できる場合にはコンパイルエラーになる
      • // Set first day of week let first = days[0]; // Set second day of week let second = days[1]; // Set seventh day of week, use wrong index - should be 6 let seventh = days[7]; // コンパイルエラー
  • ベクター (翻訳の表記が揺れているがベクターにしておく)
    • ベクターの概念
      • 配列は固定長だが、ベクターは可変長
      • <vector>u32<vector>String のように作成する
      • 型がわかっていない場合には、 <vector><T> のようにジェネリック(未知)データ型で定義できる
    • マクロを使ったベクターの初期化
      • vec! というマクロを使って、配列からベクターを作成できる
      • // Declare vector, initialize with three values let three_nums = vec![15, 3, 46]; println!("Initial vector: {:?}", three_nums); // Declare vector, first value = "0", length = 5 let zeroes = vec![0; 5]; println!("Zeroes: {:?}", zeroes);
    • Vector::new() による初期化
      • new() メソッドで空のベクターが作成できる
      • 要素の追加などをしたい場合は、mut にする必要がある
      • // Create empty vector, declare vector mutable so it can grow and shrink let mut fruit = Vec::new();
    • プッシュとポップ
      • push(<value>) を使って一番後ろに値を追加できる。
      • ジェネリックで作成した場合、最初に push した値で型が確定
      • 以降は同じ型のものしか入れられない
      • // Push values onto end of vector, type changes from generic `T` to String fruit.push("Apple"); fruit.push("Banana"); fruit.push("Cherry"); println!("Fruits: {:?}", fruit); fruit.push(1); // コンパイルエラー
      • pop() を使って値を取り出せる
      • 取り出すのも後ろから。
      • push, pop なので FILO バッファになる
      • // Pop off value at end of vector // Call pop() method from inside println! macro println!("Pop off: {:?}", fruit.pop()); println!("Fruits: {:?}", fruit);
    • ベクターのインデックス
      • 要素アクセスは配列と同じ
      • // Declare vector, initialize with three values let mut index_vec = vec![15, 3, 46]; let three = index_vec[1]; println!("Vector: {:?}, three = {}", index_vec, three);
      • 範囲外アクセスした場合には、パニックが発生
      • // Access vector with out-of-bounds index let beyond = index_vec[10]; println!("{}", beyond); パニックメッセージ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 10', src/main.rs:7:18
  • ハッシュマップ
    • ハッシュマップの作成
      • HashMap<K, V> の形式
      • ベクターと同様に拡大可能
      • use で HashMap を入れる必要あり
      • key, value を追加できるようにするには mut を付ける
      • Hash は .insert で key, value を追加
      • toString() は String の実態を作成するメソッド。Hash が実態を所有する必要があるため
      • use std::collections::HashMap; let mut reviews: HashMap<String, String> = HashMap::new(); reviews.insert("Ancient Roman History".to_string(), "Very accurate.".to_string()); reviews.insert("Cooking with Rhubarb".to_string(), "Sweet recipes.".to_string()); reviews.insert("Programming in Rust".to_string(), "Great examples.".to_string());
    • 値の取得
      • get() で値を取得できる
      • get の引数は参照文字列(&str)で良いので、直接 "Programming in Rust" でもよい
      • この例ではそのことを理解させるために、book という変数に入れている(型は &str)
      • get の返り値は取得できない場合もあるので、Optional になるとのこと。
      • Rust では Some(中身) という形になるらしい
      • Optional の外し方はまだ説明はない
      • // Look for a specific review let book: &str = "Programming in Rust"; println!("\nReview for \'{}\': {:?}", book, reviews.get(book)); 結果 Review for 'Programming in Rust': Some("Great examples.")
    • 値の削除
      • remove() で値を削除できる
      • 削除したものを get すると None になる
      • // Remove book review let obsolete: &str = "Ancient Roman History"; println!("\n'{}\' removed.", obsolete); reviews.remove(obsolete); // Confirm book review removed println!("\nReview for \'{}\': {:?}", obsolete, reviews.get(obsolete)); 結果 'Ancient Roman History' removed. Review for 'Ancient Roman History': None
ループを使用したデータの反復処理 - Learn
多くの場合、プログラムには、その場で繰り返す必要があるコードのブロックがあります。 ループ式を使用して、繰り返しの実行方法をプログラムに指示できます。 電話帳のすべてのエントリを出力するには、ループ式を使用して、最初のエントリから最後のエントリまでを出力する方法をプログラムに指示できます。 Rust には、プログラムがコードのブロックを繰り返すようにする 3 つのループ式が用意されています。 loop: 手動で停止されない限り、繰り返します。 while: 条件が true の間は繰り返します。 for: コレクション内のすべての値に対して繰り返します。 このユニットでは、これらの各ループ式について見ていきます。 loop 式では、無限ループが作成されます。 このキーワードを使用すると、式本体のアクションを継続的に繰り返すことができます。 アクションは、ループを停止する直接アクションを実行するまで繰り返されます。 次の例では、"We loop forever!" というテキストが出力されます。 独力では停止しません。 println! アクションが繰り返され続けます。 loop { println!("We loop forever!"); } loop 式を使用する場合、ループを停止する唯一の方法は、プログラマが直接介入することです。 特定のコードを追加してループを停止させることができます。または、Ctrl+C などのキーボード命令を入力して、プログラムの実行を停止することもできます。 loop 式を停止する最も一般的な方法は、 break キーワードを使用してブレーク ポイントを設定することです。 loop { // Keep printing, printing, printing...
ループを使用したデータの反復処理 - Learnループを使用したデータの反復処理 - Learn
  • Rust のループは3つ
    • loop: 無限ループ
    • whlie: 条件が true の間ループ
    • for: コレクションを順にループ
  • loop
    • break まで止まらない
    • loop 自体も値を返せる
    • break の後に返す値を示せる
    • break が複数ある場合には、全てが同じ型でないとエラーになる
    • 値が明示的に返されなかった場合には、空のタプルが返却される
    • let mut counter = 1; // stop_loop is set when loop stops let stop_loop = loop { counter *= 2; if counter > 100 { // Stop loop, return counter value break counter; } }; // Loop should break when counter = 128 println!("Break the loop at counter = {}.", stop_loop);
  • while
    • 条件を満足する間ループする
    • let mut counter = 0; while counter < 5 { println!("We loop a while..."); counter = counter + 1; }

次のページはこちら
Rust 学習記録(2)