はじめての Rust 入門 Part2 ~関数と制御フローについて学ぶまで~

はじめての Rust 入門 Part2 ~関数と制御フローについて学ぶまで~

link です。

高速でセキュリティ的にも安全な言語として Rust が注目を集めています。

今回はそんな Rust の勉強をしていきます。

本記事は Part1 の続きになっています。

想定環境

  • Windows 11
  • Rust 1.72

関数

Rust における関数について勉強していきます。

Rust の関数名は スネークケース(hello_world のように全文字を小文字にし、単語区切りにアンダースコアを使う) で命名するのが慣例です。

関数の基本

Rust において関数定義は、 fn で始まります。

C や Java のように関数名の後に () が続き、 {} が関数の処理内容を指定します。

関数例
fn main() {
    test_function();
}

fn test_function() {
    println!("テスト");
}

関数例では main() の後ろで test_function() を定義していますが、関数の定義場所はどこでも問題ありません。

どこかで定義されてさえいれば問題ありません。

関数の引数

引数付きの関数は () 内に型付きの変数を入れます。

引数付きの関数
fn main() {
    test_function(5);
}

fn test_function(x: i32) {
    println!("The value of x is: {}", x);
}

実行結果は以下のようになります。

実行結果
$ ./main.exe
The value of x is: 5

関数の式について

Rust の関数はから形成されます。

文は何らかの動作をして値を返さない命令、つまり、変数に代入できないものです。

式は値が評価され、戻り値として返ってくる命令、つまり、変数に代入できるものです。

以下にコード例を示します。

文と式
fn main() {
    let x = {
        let y = 3;
        y + 2 // y + 2 (= 5) が評価され、 x に y + 2 の値が代入される
    };

    println!("The value of y is: {}", x);
}

Rust では +-*/% などの演算以外に関数呼び出し、マクロ呼び出し、新しいスコープを作る際に使用する {} も式です。

上の例では x に代入している {} が式です。 println!("The value of y is: {}", x); が文です。

{} の中身の文末にあるセミコロンがついていない行に注意してください。

式は終端にセミコロンを含みません。式の終端にセミコロンを付けたら、文に変えてしまいます。

Rust において文は値を返しません。

関数の戻り値

Rust の関数で戻り値を返す時は -> で型を指定します。

Rust では関数の戻り値は関数の最後の式の値と同義です。

return でも値を指定できますが、多くの関数は最後の式を暗黙的に返します。

また Rust の関数で戻り値を返さない場合は関数内の処理を実行するだけの文になります。

以下に値を返す関数の例を示します。

戻り値
fn five() -> i32 {
    5
}

fn ex_return() -> i32 {
    return 10;
}

fn main() {
    let x = five();
    let y = ex_return();

    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

five() では let すら使わずに戻り値の 5 だけが存在しています。

これでも Rust では問題ありません。

セミコロンがないため、式として成立しています。

ex_return() はセミコロン付きの return で値を返しています。

return で戻り値を返す場合はセミコロンがあっても、値自体は返されるため、式になります。

制御フロー

条件が真かどうかによってコードを走らせるかどうかを決定したり、 条件が真の間繰り返しコードを走らせるか決定したりする制御フローについて勉強します。

if 文

if 文は条件に応じて実行するかしないかを判別します。

Rust の if 文は if 条件式 {実行処理} で書かれます。

他のプログラミング言語のように else if で複数の条件に応じて処理内容を変えることや else で条件を満たさない場合の処理の指定もできます。

以下に例を示します。

if文
fn main() {
    let number = 3;

    if number < 5 {
        println!("5 未満");
    } else if number <= 10 {
        println!("5 以上 10 以下");
    } else {
        println!("それ以外");
    }
}

if 文の条件は論理値であればよいため、たとえば let bool = true と定義された変数をそのまま条件式に利用できます。

また、 let 内で if 文を使用できます。

下記の例では condition の値に応じて number に代入される値が 5 か 6 かが変わります。

let内でif文を使う
fn main() {
    let condition = true;
    let number = if condition { 5 } else { 6 };

    println!("The value of number is: {}", number);
}

loop 文

loop 文は break で明示的に終了させるまで処理を繰り返し実行させ続けます。

以下にコード例を示します。

loop文
fn main() {
    let mut i = 0;
    loop {
        i += 1;
        if i = 9 {
            break;
        }
    }
    println!("end: {}", i);
}

上記の例では i に 1 ずつ加算していき、 9 になるとループを終了するようになっています。

また、強制的に次のループに移行させる continue も存在します。

ループ内にループがある場合、 breakcontinue は最も内側のループに適用されます。

ループラベルを使用することで breakcontinue が適用されるループを指定できます。

以下に例を示します。

ループラベル
fn main() {
    let mut count = 0;
    'counting_up: loop {
        println!("count = {}", count);
        let mut remaining = 10;

        loop {
            println!("remaining = {}", remaining);
            if remaining == 9 {
                break;
            }
            if count == 2 {
                break 'counting_up;
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {}", count);
}

上記の例では外側のループには 'counting_up というラベルがついていて、 0 から 2 までカウントアップします。

内側のラベルのないループは 10 から 9 までカウントダウンします。

最初のラベルのない break は内側のループを終了させます。

break 'counting_up; は外側のループを終了させます。

while 文

while 文は指定した条件が真でなくなった時にループを終了します。

以下の例では 0 になるまでカウントダウンしてループを終了しています。

while文
fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{}", number);

        number -= 1;
    }
    println!("end");
}

for 文

配列を順に取得する必要がある場合、 for 文を使ってループさせることができます。

以下の例では配列 a から順に値を表示させています。

for文
fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {}", element);
    }
}

参考サイト

まとめ

今回は関数と制御フローについて勉強しました。

次回は Rust の特徴的な概念である所有権について勉強していきます。

それではまた、別の記事でお会いしましょう。

linkohta