コンテンツにスキップ

Rustの関数

関数(function)は、名前を付けて何度でも使えるようにしたコードのかたまりです。同じ手順を何度も書く代わりに、一度関数にまとめておけば、必要なときにいつでも呼び出せます。実は、もうすでに1つ使っています。main です。

関数は fn で定義し、名前の後ろに () を付けて呼び出します。

fn greet() {
println!("関数からこんにちは!");
}
fn main() {
greet(); // 呼び出す
greet(); // もう一度呼び出す
}

実行結果:

関数からこんにちは!
関数からこんにちは!
▶ 実際に試してみよう

関数は、処理するデータを渡せるようになると一気に便利になります。この入力を引数(パラメータ)と呼びます。Rustでは、引数にはそれぞれ型を必ず書かなければなりません。

fn greet(name: &str) {
println!("こんにちは、{name}さん!");
}
fn main() {
greet("アリス");
greet("ボブ");
}

実行結果:

こんにちは、アリスさん!
こんにちは、ボブさん!
▶ 実際に試してみよう

引数は、カンマで区切っていくつでも書けます。

fn describe(name: &str, age: u32) {
println!("{name}は{age}歳です");
}
fn main() {
describe("Ferris", 10);
}

実行結果:

Ferrisは10歳です
▶ 実際に試してみよう

渡した値は、位置によって引数に割り当てられます。1つ目の値は name に、2つ目は age に入ります。describe(10, "Ferris") のように順番を間違えて渡すと、型が合わないのでコンパイルエラーになります。

関数は、呼び出した側に値を返せます。戻り値の型は、矢印 -> の後ろに書きます。

fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = add(3, 4);
println!("3 + 4 = {sum}");
}

実行結果:

3 + 4 = 7
▶ 実際に試してみよう

セミコロンのルール(大事!)

Section titled “セミコロンのルール(大事!)”

上の例の a + b にはセミコロンがないことに気づきましたか? これはRustの大切な考え方です。

  • セミコロンなしの式は、そのまま返される値になります。
  • セミコロンを付けると文(statement)になり、何も返さなくなります。

なので、次のコードは動きません。

fn add(a: i32, b: i32) -> i32 {
a + b; // ❌ セミコロンがあると「何も返さない」ことになる。でも i32 を返すと約束している
}

コンパイラは「この関数は i32 を返すはずなのに返していない」とエラーを出します。最後の行のセミコロンを消せば直ります。

fn square(n: i32) -> i32 {
n * n
}
fn main() {
let result = square(5);
println!("5の2乗は{result}です");
}

実行結果:

5の2乗は25です
▶ 実際に試してみよう

摂氏の温度を f64 で受け取り、華氏に変換して返す関数 to_fahrenheit を書いてください。式は c * 9.0 / 5.0 + 32.0 です。0度、100度、37度で呼び出してみましょう。ヒント:シグネチャは fn to_fahrenheit(c: f64) -> f64 で、本体はセミコロンのない式1つだけです。

解答を見る
fn to_fahrenheit(c: f64) -> f64 {
c * 9.0 / 5.0 + 32.0
}
fn main() {
println!("0°Cは{}°Fです", to_fahrenheit(0.0));
println!("100°Cは{}°Fです", to_fahrenheit(100.0));
println!("37°Cは{}°Fです", to_fahrenheit(37.0));
}

実行結果:

0°Cは32°Fです
100°Cは212°Fです
37°Cは98.6°Fです
▶ 実際に試してみよう

0 ではなく 0.0 を渡していることに注目してください。引数は f64 で、Rustは整数を勝手に浮動小数点数に変えてはくれません。f64 に小数部分がないとき、{} は .0 を付けずに表示します。だから 32.0 ではなく 32 と表示されるのです。

3つの数のうちいちばん大きいものを返す関数 largest(a: i32, b: i32, c: i32) -> i32 を書いてください。(3, 9, 4) と (-2, -8, -5) で試しましょう。ヒント:Rustでは if は式です(if / elseを参照)。なので、if / else if / else のチェーンを関数の最後の行にできます。

解答を見る
fn largest(a: i32, b: i32, c: i32) -> i32 {
if a >= b && a >= c {
a
} else if b >= c {
b
} else {
c
}
}
fn main() {
println!("{}", largest(3, 9, 4));
println!("{}", largest(-2, -8, -5));
}

実行結果:

9
-2
▶ 実際に試してみよう

どの分岐もセミコロンで終わっていません。それぞれが式になっていて、if のチェーン全体がそのうちの1つを返し、それが戻り値になります。> ではなく >= を使っているので、同じ値が並んだときもちゃんと値を返せます。

  • 関数は fn で定義し、名前() で呼び出します。
  • 引数は関数への入力で、それぞれに型が必要です(fn greet(name: &str))。
  • 戻り値の型は -> 型 で宣言します。
  • セミコロンのない最後の式が戻り値になります。
  • return 値; も使えますが、ふつうは途中で早めに返したいときに使います。

理解度チェック

1. Rustでは、関数の引数それぞれに型を書く必要がありますか?

2. 関数の戻り値の型はどう宣言しますか?

3. 関数の最後にある a + b(セミコロンなし)が戻り値になるのはなぜですか?

4. 関数を呼び出し位置の上に定義するか下に定義するか(たとえば main の上か下か)は関係ありますか?

スコア: 0 / 4