関数
処理をまとめて再利用可能にする「関数」について学びます。
関数とは
関数は「処理をまとめた部品」です。
fn main() {
greet(); // 関数を呼び出す
}
fn greet() {
println!("こんにちは!");
}
なぜ関数を使うのか
- 再利用: 同じ処理を何度も書かなくて済む
- 整理: コードを意味のある単位に分割
- テスト: 部品ごとにテストしやすい
関数の定義
#![allow(unused)]
fn main() {
fn 関数名() {
// 処理
}
}
fn: 関数を定義するキーワード関数名: snake_case で命名(): 引数リスト{}: 関数の本体
命名規則
#![allow(unused)]
fn main() {
fn calculate_total() { } // OK: snake_case
fn calculateTotal() { } // 動くが警告が出る
}
Rustでは関数名に snake_case(小文字とアンダースコア)を使います。
引数
関数にデータを渡せます。
fn main() {
greet("太郎");
greet("花子");
}
fn greet(name: &str) {
println!("こんにちは、{}さん!", name);
}
出力:
こんにちは、太郎さん!
こんにちは、花子さん!
引数の書き方
#![allow(unused)]
fn main() {
fn 関数名(引数名: 型) {
// 処理
}
}
型注釈は必須です。省略できません。
複数の引数
fn main() {
print_sum(5, 3);
}
fn print_sum(a: i32, b: i32) {
println!("{} + {} = {}", a, b, a + b);
}
戻り値
関数は値を返すことができます。
fn main() {
let result = add(5, 3);
println!("結果: {}", result);
}
fn add(a: i32, b: i32) -> i32 {
a + b // セミコロンなし = この値を返す
}
戻り値の書き方
#![allow(unused)]
fn main() {
fn 関数名(引数) -> 戻り値の型 {
戻り値 // セミコロンなし
}
}
->: 戻り値の型を示す- 最後の式の値が返される(セミコロンをつけない)
return を使う方法
#![allow(unused)]
fn main() {
fn add(a: i32, b: i32) -> i32 {
return a + b; // 明示的にreturn
}
}
return を使うと、関数の途中でも値を返して終了できます:
#![allow(unused)]
fn main() {
fn absolute(n: i32) -> i32 {
if n < 0 {
return -n; // ここで終了
}
n // nが0以上の場合
}
}
式と文
Rustではセミコロンの有無が重要です。
fn main() {
let x = {
let y = 3;
y + 1 // セミコロンなし → これが式の値になる
};
println!("{}", x); // 4
}
fn main() {
let x = {
let y = 3;
y + 1; // セミコロンあり → 値を返さない(()を返す)
};
// xは () 型になる
}
| 式(Expression) | 文(Statement) | |
|---|---|---|
| セミコロン | なし | あり |
| 値を返す | はい | いいえ |
| 例 | 5 + 3, x * 2 | let x = 5;, x = 3; |
関数を使った例
例1: 面積の計算
fn main() {
let width = 10;
let height = 5;
let area = calculate_area(width, height);
println!("面積: {}", area);
}
fn calculate_area(width: i32, height: i32) -> i32 {
width * height
}
例2: 偶数判定
fn main() {
for i in 1..=10 {
if is_even(i) {
println!("{}は偶数", i);
}
}
}
fn is_even(n: i32) -> bool {
n % 2 == 0
}
例3: 最大値を求める
fn main() {
let max = maximum(10, 25);
println!("最大値: {}", max);
}
fn maximum(a: i32, b: i32) -> i32 {
if a > b {
a
} else {
b
}
}
関数の設計指針
1. 一つのことをうまくやる
#![allow(unused)]
fn main() {
// 良い例:一つのことに集中
fn calculate_tax(price: i32) -> i32 {
price / 10
}
fn calculate_total(price: i32, tax: i32) -> i32 {
price + tax
}
// 悪い例:複数のことをやっている
fn calculate_and_print_total(price: i32) {
let tax = price / 10;
let total = price + tax;
println!("税込: {}", total);
}
}
2. 適切な名前をつける
#![allow(unused)]
fn main() {
// 良い例:何をするかわかる
fn calculate_area(width: i32, height: i32) -> i32 { ... }
fn is_valid_email(email: &str) -> bool { ... }
// 悪い例:わかりにくい
fn calc(a: i32, b: i32) -> i32 { ... }
fn check(s: &str) -> bool { ... }
}
3. 引数は少なめに
引数が多すぎると使いにくくなります。3〜4個を超えたら構造体の使用を検討。
まとめ
| 要素 | 説明 |
|---|---|
fn | 関数を定義 |
| 引数 | 関数に渡すデータ。型注釈必須 |
-> | 戻り値の型を示す |
| 戻り値 | 最後の式(セミコロンなし)が返る |
return | 明示的に値を返す |
確認テスト
Q1. 関数の戻り値について正しいのは?
正解: B) Rustでは最後の式にセミコロンをつけないと、その値が関数の戻り値になります。セミコロンをつけると文になり、値を返しません。
Q2. 関数の引数について正しいのは?
正解: B) 関数の引数には必ず型注釈が必要です。変数の
let では型推論が働きますが、関数の引数では明示が必須です。
Q3. double(triple(2)) の結果は?(double: n*2, triple: n*3)
正解: C) 内側の関数から先に評価されます。triple(2)=6、次にdouble(6)=12となります。
Q4. fn add(a: i32, b: i32) -> i32 { a + b; } のエラーを修正するには?
正解: A) セミコロンがついていると式ではなく文になり、値を返しません。セミコロンを削除するか、
return a + b; とします。
Q5. FizzBuzz問題で「15」は何と出力される?
正解: D) 15は3の倍数かつ5の倍数なので「FizzBuzz」と出力されます。両方の条件を満たす場合を先に判定する必要があります。
次のドキュメント: 05_collections_basic.md