チュートリアル

Rust基礎:条件分岐とループ

Rust入門制御構文
広告エリア

条件分岐

if式

Rustのifは式であり、値を返すことができます。

let age = 20;

if age >= 20 {
    println!("成人です");
} else if age >= 13 {
    println!("ティーンエイジャーです");
} else {
    println!("子供です");
}

// if式として使用
let status = if age >= 20 { "成人" } else { "未成年" };
println!("{}", status);

if let

let some_value: Option<i32> = Some(42);

// パターンマッチングの簡略版
if let Some(value) = some_value {
    println!("値: {}", value);
} else {
    println!("値がありません");
}

// Resultでも使える
let result: Result<i32, &str> = Ok(100);
if let Ok(n) = result {
    println!("成功: {}", n);
}

match式

let number = 3;

match number {
    1 => println!("一"),
    2 => println!("二"),
    3 => println!("三"),
    4 | 5 => println!("四または五"),
    6..=10 => println!("六から十"),
    _ => println!("その他"),
}

// 値を返す
let word = match number {
    1 => "one",
    2 => "two",
    3 => "three",
    _ => "other",
};

パターンマッチング

// タプル
let point = (0, 5);

match point {
    (0, 0) => println!("原点"),
    (0, y) => println!("y軸上: y = {}", y),
    (x, 0) => println!("x軸上: x = {}", x),
    (x, y) => println!("点: ({}, {})", x, y),
}

// 構造体
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 0, y: 7 };

match p {
    Point { x: 0, y } => println!("y軸上: y = {}", y),
    Point { x, y: 0 } => println!("x軸上: x = {}", x),
    Point { x, y } => println!("点: ({}, {})", x, y),
}

// ガード条件
let num = Some(4);

match num {
    Some(x) if x < 5 => println!("5未満: {}", x),
    Some(x) => println!("5以上: {}", x),
    None => println!("なし"),
}

Option と Result のマッチング

// Option
fn find_user(id: u32) -> Option<String> {
    if id == 1 {
        Some(String::from("太郎"))
    } else {
        None
    }
}

match find_user(1) {
    Some(name) => println!("見つかりました: {}", name),
    None => println!("見つかりませんでした"),
}

// Result
fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("ゼロ除算"))
    } else {
        Ok(a / b)
    }
}

match divide(10, 2) {
    Ok(result) => println!("結果: {}", result),
    Err(e) => println!("エラー: {}", e),
}

ループ

loop

// 無限ループ
loop {
    println!("ループ");
    break;  // breakで抜ける
}

// ループから値を返す
let result = loop {
    let value = get_value();
    if value > 10 {
        break value * 2;  // 値を返して終了
    }
};

while

let mut count = 0;

while count < 5 {
    println!("{}", count);
    count += 1;
}

// while let
let mut stack = vec![1, 2, 3];

while let Some(top) = stack.pop() {
    println!("{}", top);
}

for

// 範囲
for i in 0..5 {
    println!("{}", i);  // 0, 1, 2, 3, 4
}

for i in 0..=5 {
    println!("{}", i);  // 0, 1, 2, 3, 4, 5
}

// 逆順
for i in (0..5).rev() {
    println!("{}", i);  // 4, 3, 2, 1, 0
}

// コレクション
let numbers = vec![1, 2, 3, 4, 5];

for num in &numbers {
    println!("{}", num);
}

// インデックス付き
for (index, value) in numbers.iter().enumerate() {
    println!("{}: {}", index, value);
}

// 変更可能な参照
let mut numbers = vec![1, 2, 3];
for num in &mut numbers {
    *num *= 2;
}

break と continue

// break
for i in 0..10 {
    if i == 5 {
        break;
    }
    println!("{}", i);
}

// continue
for i in 0..10 {
    if i % 2 == 0 {
        continue;
    }
    println!("{}", i);  // 奇数のみ
}

// ラベル付きbreak
'outer: for i in 0..3 {
    for j in 0..3 {
        if i == 1 && j == 1 {
            break 'outer;
        }
        println!("i={}, j={}", i, j);
    }
}

イテレータ

let numbers = vec![1, 2, 3, 4, 5];

// map
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();

// filter
let evens: Vec<&i32> = numbers.iter().filter(|x| *x % 2 == 0).collect();

// fold(畳み込み)
let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);

// チェーン
let result: i32 = numbers
    .iter()
    .filter(|x| *x % 2 == 1)
    .map(|x| x * 2)
    .sum();

実践例:FizzBuzz

fn main() {
    for i in 1..=30 {
        let result = match (i % 3, i % 5) {
            (0, 0) => String::from("FizzBuzz"),
            (0, _) => String::from("Fizz"),
            (_, 0) => String::from("Buzz"),
            _ => i.to_string(),
        };
        println!("{}", result);
    }
}

実践例:数当てゲーム

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    let secret = rand::thread_rng().gen_range(1..=100);
    println!("1から100までの数を当ててください");

    loop {
        println!("入力: ");
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("読み取りエラー");

        let guess: u32 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("数字を入力してください");
                continue;
            }
        };

        match guess.cmp(&secret) {
            Ordering::Less => println!("もっと大きい"),
            Ordering::Greater => println!("もっと小さい"),
            Ordering::Equal => {
                println!("正解!");
                break;
            }
        }
    }
}

まとめ

  • ifは式であり値を返せる
  • matchで強力なパターンマッチング
  • if letwhile letでパターンの簡略化
  • loopは無限ループ、値を返せる
  • forで範囲やコレクションをイテレート
  • break/continueにラベルを付けられる
  • イテレータメソッドで関数型スタイル

次回は関数について学びます。

広告エリア