Rustの関数を徹底解説!定義、引数、戻り値、文と式…
こんにちは!今日もRustの学習記録です。
引き続き、The Rust Programming Language 日本語版 (通称 “The Book”) を読み進めていきます。
今回は、The Bookの「関数」の章を学びます。
(3.3. 関数 – The Rust Programming Language 日本語版)
Rustの関数:基本の形
Rustのプログラムにおいて、main
関数は特別な関数であり、多くのプログラムでエントリーポイント(最初に実行される関数)となります。
fn main() {
// メイン関数ブロック
sub_function(); // 関数の呼び出し
}
fn sub_function() {
// サブ関数ブロック
println!("sub_function関数が呼び出されました");
}
新しい関数を宣言するには、fn
キーワードを使用します。
Rustでは、関数名と変数名にはスネークケース (snake_case) を使うのが慣例です。
スネークケースとは、全て小文字で、単語の区切りにアンダースコア (_
) を使う書き方です。
関数の定義は、
fn
キーワード- 関数名
()
{
関数本体}
という形になります。
Rustのコンパイラは、関数がどこで定義されているか (呼び出し元より前か後か) は気にしません。
fn sub_function() {
println!("sub_functionの呼び出し、前配置");
}
fn main() {
sub_function();
next_function();
}
fn next_function() {
println!("next_functionの呼び出し、後配置");
}
出力結果:
sub_functionの呼び出し、前配置 next_functionの呼び出し、後配置
もちろん、関数の中で別の関数を呼び出すことも可能です。
fn sub_function() {
println!("sub_functionの呼び出し、前配置");
}
fn main() {
next_function();
}
fn next_function() {
println!("next_functionの呼び出し、後配置");
sub_function(); // 関数の中で関数の呼び出し
}
出力結果:
next_functionの呼び出し、後配置 sub_functionの呼び出し、前配置
関数の引数
関数は、引数 (ひきすう) を持つように定義できます。
引数には、
- 仮引数 (parameter): 関数定義側の引数
- 実引数 (argument): 関数呼び出し側の引数
の2種類がありますが、日本語では特に区別せず、どちらも「引数」と呼ぶことが多いです。
fn sub_function(x: i32) { // x が仮引数
println!("数字は{}", x);
}
fn main() {
sub_function(10); // 10 が実引数
}
出力結果:
数字は10
Rustでは、関数の仮引数の型は必ず宣言しなければなりません。これは、Rustの安全性と明確性を高めるための設計上の決定です。
複数の引数を持つ場合は、カンマ (,
) で区切ります。
fn sub_function(x: i32, y: char) {
println!("数字の{}と文字の{}", x, y);
}
fn main() {
sub_function(10, 't');
}
出力結果:
数字の10と文字のt
文 (statement) と式 (expression)
Rustの関数本体は、文 (statement) と式 (expression) から構成されます。
この違いを理解することは、Rustのコードを読み書きする上で非常に重要です。
…とは言え、最初はちょっとややこしいので、AI (Gemini) に解説してもらいました。
AI:
- 文 (Statement):
- 何らかの処理を行う命令であり、値を返しません。
- 主に、変数の宣言や代入、制御構造 (
if
,for
など) が該当します。- Rustでは、文の末尾にはセミコロン (
;
) をつけるのが一般的です。- 式 (Expression):
- 評価されると何らかの値を返します。
- 算術演算、関数呼び出し、ブロック (
{}
) などが該当します。- 式の末尾にはセミコロン (
;
) をつけません。
具体例を見てみましょう。
fn main() {
let y = 6; // 文 (変数宣言)
let x = {
let x = 3;
x + 1 // 式 (ブロックの最後の式)
};
println!("The value of x is: {}", x); // 4
println!("The value of y is: {}", y); // 6
}
let y = 6;
は文です。変数y
に値6
を代入する命令であり、値を返しません。{ let x = 3; x + 1 }
はブロックであり、式です。ブロック内の最後の式x + 1
の結果である4
が、ブロック全体の評価結果となります。let x = (let y = 6);
はエラーになります。let y = 6
は文であり、値を返さないためです。
Rustは式指向言語であり、多くの構文が式として扱われます。
この特徴により、Rustでは簡潔で表現力豊かなコードを記述できます。
セミコロン (;) の有無に注意:
式の末尾にセミコロンを付けると、文に変わります。文は値を返さないため、注意が必要です。
関数の戻り値
関数の戻り値とは、関数が処理を行った結果として呼び出し元に返す値のことです。
Rustでは、
- 関数の戻り値の型は、関数シグニチャ (関数定義の最初の行) の中で、矢印 (
->
) の後に宣言します。 - 関数内で
return
キーワードを使って値を返すことができます。 return
を省略した場合、関数本体の最後の式の評価結果が自動的に戻り値となります。
fn add(x: i32, y: i32) -> i32 {
let a = 3;
let b = 4;
let s = a + b;
x + y // 最後の式が戻り値
}
fn main() {
let result = add(5, 3);
println!("5 + 3 = {}", result); // 出力: 5 + 3 = 8
}
add
関数の中で変数 a
, b
, s
についての計算を行っていますが、
結果として返される値は、最後の式 x + y
の評価結果です。
関数内で複数の値を返すような式はコンパイルエラーになります。
コンパイラは最初に見つかった式の型を戻り値と推測するため、returnキーワードが使用されていない場合は、関数の戻り値は最後に評価される「式」の結果となります。
return
文は、関数のどこに書かれていても有効です。
return
文が実行されると、その時点で関数は終了し、値を返します。
関数の戻り値の型宣言と、returnで返される値の型が一致しない場合はエラーとなります。
注意
関数内で複数の値を返す式があるとコンパイルエラーになります。
関数内でreturn文を使わなかった場合、最後の式の評価結果が戻り値となります。途中の処理は戻り値に影響しません。
今回の学習を終えて
今回は、The Bookの「関数」の章を読み、Rustの関数の基本について学びました。
特に、
- 関数の定義方法 (
fn
キーワード、スネークケース) - 引数の扱い (仮引数と実引数、型宣言)
- 文と式の違い
- 戻り値の扱い (
->
での型宣言、最後の式、return
)
は、Rustプログラミングの基礎となる重要な概念です。
次回は、制御フロー (if
, for
, while
) について学習する予定です。
それが終わったら、簡単なプログラムを作りながら、今回学んだ関数や、以前に学んだデータ型などを復習していこうと思います。
//を使うとその行をコメントアウトすることができる。ということもわかりました。
Rustはエラー時にコメントがわかりやすくてとても良いですね。
英語ではあるけど、
mismatched typesとか
consider removing this semicolonとか
英語苦手だけどなんとなく言ってる意味がわかるのでエラーが出た時はしっかりとエラー文を読むことで解決に繋がりそう。