条件分岐
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 letとwhile letでパターンの簡略化loopは無限ループ、値を返せるforで範囲やコレクションをイテレートbreak/continueにラベルを付けられる- イテレータメソッドで関数型スタイル
次回は関数について学びます。