「Rust」の基本的な文法を知ろう

2023年10月20日(金)
大西 武 (オオニシ タケシ)
第3回の今回は、「変数」「データ型」「if文」「for文」「関数」「構造体」といった「Rust」の基本的な文法を解説します。

「制御構文」について

「制御構文」とは、条件に応じて処理を分岐する「条件分岐構文」と、ある条件のもとで処理を繰り返す「ループ処理構文」のことです。C++とよく似た制御構文です。条件分岐構文には「if文」「match文」があり、ループ処理構文には「for文」「while文」「loop文」があります。

match文に関しては、C++でいう「switch文」に近い制御構文と言えばピンとくるでしょう。また、match文は分岐するパターンを1つ選ぶのに「enum列挙型」を使うことがあります。

普通は、制御構文を組み合わせて複雑な処理を書き、上から順に流れるプログラムの流れを変えて制御します。ただし、筆者はできるだけシンプルにコードを書いた方が良いと思います。

Rustに限ったことではありませんが、プログラミング言語は文法だけを見るよりサンプルを見て使い方の参考にした方が理解が早まると思います。筆者の場合は最小限の数行のサンプルコードではなく、実際に動作するミニゲームのサンプルコードを改造しながら自然と文法を身に付けることが多いです。なぜなら目に見えて動作が変化するのが分かると理解が深まるからです。

「if文」について

if文は、文字通り「もし◯◯なら△△する」という「条件分岐」する制御構文です。他のプログラミング言語では条件を「()」でくくることが多いですが、Rustでは不要です。

実際には、次のサンプルコードのようにif文を書きます。

・「if文」のサンプルコード
fn main() {
    if 1 < 2 {
        println!("1は2より小さい");
    }
}

【サンプルコードの解説】
「if 1 < 2」で1が2より小さい条件が成り立つので、直後の「{}」内の処理が実行され"1は2より小さい"をターミナルに表示します。

さらに「もし◯◯なら△△するが、◯◯でない場合□□する」という条件が成り立たない場合の条件分岐も「else if文」や「else文」の制御構文でできます(図3)。次のサンプルコードのように「if-else文」を書きます。

図3:「if文」~「else if文」~「else文」で条件分岐

・「if-else文」のサンプルコード
fn main() {
    let i = 3;
    if i < 1 {
        println!("iは1より小さい");
    } else if i < 2 {
        println!("iは2より小さい");
    } else {
        println!("iは2以上");
    }
}

【サンプルコードの解説】
「if i < 1 {」でiが1より小さいことが成り立たないので、その場合は「} else if i < 2 {」が比較されますが、iが2より小さいことも成り立たないので、その場合はさらに「} else {」以降の処理が実行されます。よって"iは2以上"をターミナルに表示します。

「for文」について

for文とは、決まった回数だけループする繰り返し処理の制御構文のことです。他のプログラミング言語では条件を「()」でくくることが多いですが、Rustでは不要です。最もシンプルな「range(範囲)」は「0..3」のように0から始まり3未満で終わるように書きます。rangeを「0..=3」とすると0~3以下の整数を繰り返します。for文にif文を組み合わせたりして、より複雑な処理もできます。

次のサンプルコードのようにfor文を書くと、「println!」マクロは1回しか書かれていないのに、繰り返しでターミナルに3行表示します(図4)。

図4:ターミナルに「for文」で繰り返し表示

・「for文」のサンプルコード
fn main() {
    for n in 0..3 {
        println!("{}回目",n);
    }
}

【サンプルコードの解説】
1行でこのサンプルを表すと、3回「for」ループして「0回目」「1回目」「2回目」とターミナルに表示します。「for n in 0..3」で0~3未満の範囲の整数を「n」変数に代入して、直後の「{}」内の処理を繰り返します。ここでは「0回目」「1回目」「2回目」とターミナルに表示します。

「while文」について

while文とは、条件が成り立つ限りループし続ける制御構文のことです。他のプログラミング言語では条件を「()」でくくることが多いですが、Rustでは不要です。次のサンプルコードで「continue文」が出てきますが、この文はfor文やloop文の中でも使えます。while文にif文を組み合わせたりして、より複雑な処理もできます。

「println!」マクロは1回しか書かれていないのに、繰り返し処理することで2行表示します(図5)。

図5:ターミナルに「while文」で繰り返し表示

・「while文」と「continue文」のサンプルコード
fn main() {
    let mut i = 0;
    while i < 3 {
        i += 1;
        if i == 2 { continue; }
        println!("{}回目",i);
    }
}

【サンプルコードの解説】
1行でこのサンプルを表すと、3回「while」ループで2回目のループは途中でスキップして「1回目」「3回目」とターミナルに表示します。
「可変(mut)」の「i」変数に0を代入して「let」で宣言します。「while i < 3」でiが3より小さい条件が成り立てば直後の「{}」内をループ処理します。ここでは「i」変数に1加算し、「i」変数が2に等しい場合は「continue文」で後ろの処理をスキップして「1回目」「3回目」とターミナルに表示します。

「loop文」について

loop文とは、ループし続ける制御構文のことです。次のサンプルコードで「break文」が出てきますが、この文はfor文やwhile文の中でも使えます。break文でloop文を抜け出すことでループを中断できます。loopは「while true」と同じことですが、ループのたびに条件が成り立つか調べないため、loopの方が若干処理が高速です。loop文にif文を組み合わせたりして、より複雑な処理もできます。

「println!」マクロは1回しか書かれていないのに、繰り返し処理することで3行表示します(図6)。

図6:ターミナルに「loop文」で繰り返し表示

・「loop文」と「break文」のサンプルコード
fn main() {
    let mut i = 0;
    loop {
        i += 1;
        println!("{}回目",i);
        if i == 3 { break; }
    }
}

【サンプルコードの解説】
1行でこのサンプルを表すと、無限に「loop文」で繰り返して、ターミナルに「1回目」「2回目」「3回目」と表示し、3回目のループで抜け出します。
「可変(mut)」の「i」変数に0を代入して「let」で宣言します。「loop」で直後の「{}」内を無限にループします。ループ中「i」変数に1加算し、ターミナルに「1回目」「2回目」「3回目」と表示し、「i」変数が3に等しい場合「loop文」のループを「break文」で抜け出します。

「enum列挙型」と「match文」について

選択肢を作る場合、数値だとほぼ無数にパターンが作れますが、「enum列挙型」はパターンに名前を付けてパターンを限定して1つ選ぶのに使います。enum列挙型は、次のサンプルコードのように主に「match文」でenum列挙型のパターンにマッチする「列挙子(enum列挙型で定義する定数のこと)」に分岐する制御構文に使います。

match文は全てのパターンに分岐するようにパターンを用意しなければなりません。そこで便利なのが「_(アンダーバー)」です。「_」を使うことで「それ以外(default)」を割り当てることもできます(図7)。

図7:1度も使われない「EnumType」列挙型の「Two」「Three」が警告として出ている

・「enum列挙型」と「match文」のサンプルコード
enum EnumType {
    One,
    Two,
    Three,
}

fn main() {
    let et = EnumType::One;
    match et {
        EnumType::One => println!("EnumType::One"),
        EnumType::Two => println!("EnumType::Two"),
        _ => println!("EnumType::Three")
    }
}

【サンプルコードの解説】
1行でこのサンプルを表すと、列挙型の値に「マッチ(match)」する「EnumType::One」に分岐してターミナルに"EnumType::One"と表示します。
enum列挙型の「EnumType」を宣言します。「One」「Two」「Three」の3つを列挙します。
「et」変数に「EnumType::One」列挙子を代入して「let」で宣言します。
「et」変数に「マッチ(match)」する場合分けをします。「EnumType::One」の場合(=>)、「EnumType::Two」の場合(=>)、「_(それ以外)」の場合(=>)です。ここではターミナルに"EnumType::One"と表示します。

著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。

連載バックナンバー

開発言語技術解説
第15回

「TAURI」でデータベースを使ってみよう

2024/5/10
第15回の今回は「TAURI」でオープンソースのデータベース「SQLite3」を使用して、テーブル表に表示する解説をしていきます。
開発言語技術解説
第14回

「TAURI」で気象庁の「CSVデータ」を解析する

2024/5/1
第14回の今回は気象庁のWebサイトから指定した地域の1年間の気象データをダウンロードして「TAURI」で解析していきます。
開発言語技術解説
第13回

「TAURI」で「簡易RSSリーダー」を開発してみよう

2024/4/16
第13回の今回は「TAURI」で「RSSフィード」を読み込んでWebページに一覧表示し、リンクのページを開くための新規ウィンドウを作成するところまでを解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています