Rustの関数について、どこから手をつけていいか迷っていませんか? プログラミング学習を進めていると、必ず出会うのが「関数」という概念。ぶっちゃけ、最初はちょっととっつきにくいかもしれませんね。
この記事では、Rustにおける関数の基本中の基本から、引数や戻り値といった少し応用的な使い方まで、分かりやすく解説を進めていきます。プログラムを部品化して、もっと読みやすく、もっと効率的なコードを書けるようになりましょう!
この記事を読めば、関数のナゾが解けて、きっとRustプログラミングがもっと楽しくなるはずです!
この記事で学べること
- Rustの関数がどんなものか
- 関数の基本的な書き方(定義の仕方)
- 定義した関数を呼び出す方法
- 関数に情報を渡す「引数」の使い方
- 関数から結果を受け取る「戻り値」の使い方
- 実際のコード例と、その解説
- 関数を使う上でのちょっとしたコツ
Rustの関数とは?プログラムを部品化するメリット
まず、「関数」って一体何者なのか、そこからいきましょう!
すごく簡単に言うと、関数は特定の仕事(処理)をひとまとめにした「部品」のようなものです。この部品に名前をつけておくことで、同じ仕事を何度もさせたい時に、その名前を呼ぶだけで済むようになります。
例えば、料理のレシピを思い浮かべてみてください。「野菜を切る」「材料を炒める」「味付けをする」といった工程がありますよね? 関数は、これらの工程一つひとつを「野菜切り担当」「炒め担当」「味付け担当」のように名前付きの部品にするイメージです。
関数を使うと、主にこんないいことがあります。
- コードがスッキリする
長いプログラムも、関数ごとに処理が分かれていると見通しが良くなります。 - 同じコードを何度も書かなくて済む
同じ処理が必要になったら、関数を呼び出すだけでOK。楽ちんですし、間違いも減ります。 - 修正が楽になる
もし処理内容を変更したくなっても、その関数の中だけ直せばOK。あちこち修正する必要がなくなります。
プログラムを組み立てる上で、関数はなくてはならない存在。ぜひ仲良くなりましょう!
Rustでの基本的な関数の書き方(定義方法)
では、実際にRustで関数をどうやって書くのか見ていきましょう。関数の定義は、`fn`というキーワードから始まります。
これが一番シンプルな関数の形です。
// 関数を定義する fn say_hello() { println!("Hello, Rust World!"); } // main関数(プログラムはここから始まる) fn main() { // 上で定義した関数を呼び出す(これについては次の項目で!) say_hello(); }
分解してみると、こんな感じです。
- `fn`
「これから関数を定義しますよー」という合図です。 - `say_hello`
これが関数の名前です。どんな処理をするか分かりやすい名前をつけるのがコツ。Rustでは、単語と単語の間をアンダースコア `_` でつなぐスネークケースという命名規則が一般的です。(例: `calculate_score`, `print_user_name`) - `()`
関数名の後には、必ず丸括弧がつきます。今は空ですが、後で説明する「引数」をここに書きます。 - `{}`
波括弧で囲まれた部分が、この関数が行う具体的な処理内容です。今回の例では、「Hello, Rust World!」という文字を表示する処理ですね。
まずはこの基本形を覚えましょう! `fn 名前()` `{ 処理 }` ですね。
関数を呼び出す方法
関数は定義しただけでは、その処理は実行されません。作った部品を使うには、ちゃんと「使ってね!」と呼び出す必要があります。
呼び出し方はとっても簡単。関数名に `()` をつけて書くだけです。
先ほどの `say_hello` 関数を呼び出すコードは、`main`関数の中に書かれていましたね。
fn say_hello() { println!("Hello, Rust World!"); } fn main() { println!("プログラムを開始します。"); // ここで say_hello 関数を呼び出している! say_hello(); // これで "Hello, Rust World!" が表示される println!("プログラムを終了します。"); }
これを実行すると、コンソールにはこう表示されます。
プログラムを開始します。 Hello, Rust World! プログラムを終了します。
このように、`say_hello();` と書いた場所で、`say_hello` 関数の `{}` の中の処理が実行されるわけです。簡単でしょう?
Rustの関数で引数(パラメータ)を使う
関数がただ決まった処理をするだけだと、ちょっと物足りない場面も出てきます。
例えば、「挨拶する関数」を作ったとして、いつも同じ人に挨拶するのではなく、呼び出す時に指定した人に挨拶させたいですよね?
そんな時に使うのが引数(ひきすう)です。引数は、関数に外部から情報を渡すための入り口のようなもの。関数を呼び出す時に、一緒にデータ(値)を渡すことができます。
引数を受け取る関数を定義するには、関数名の後の `()` の中に、`変数名: 型` という形式で書きます。
// `name` という名前で String 型の引数を受け取る関数 fn greet(name: String) { println!("こんにちは、{} さん!", name); } fn main() { // 関数を呼び出す時に、具体的な名前(文字列)を渡す greet("田中".to_string()); // "田中" という文字列を渡す greet("鈴木".to_string()); // "鈴木" という文字列を渡す }
この例では、`greet` 関数は `name` という名前の引数を受け取ります。そして、その型は `String` (文字列)であると指定しています。Rustでは、関数の引数には必ず型を指定する必要があることを覚えておいてくださいね。
`main`関数から `greet` 関数を呼び出す際に、`"田中".to_string()` や `"鈴木".to_string()` のように具体的な値を渡すと、それが `greet` 関数の中の `name` 変数に入り、挨拶メッセージの中で使われます。(`.to_string()` は文字列リテラルを `String` 型に変換するために付けています)
引数あり関数の定義と呼び出し例
もう少し具体例を見てみましょう。今度は、2つの数値を受け取って、その合計を表示する関数を作ってみます。
// `num1` と `num2` という2つの i32 型 (整数) の引数を受け取る関数 fn print_sum(num1: i32, num2: i32) { let sum = num1 + num2; println!("{} + {} = {}", num1, num2, sum); } fn main() { // 関数呼び出し時に、具体的な数値を2つ渡す print_sum(5, 3); // 5 と 3 を渡す print_sum(10, -2); // 10 と -2 を渡す }
実行結果はこうなります。
5 + 3 = 8 10 + -2 = 8
このように、引数はカンマ `,` で区切って複数指定できます。`print_sum` 関数は、呼び出されるたびに渡された `num1` と `num2` の値を使って計算し、結果を表示してくれます。
引数を使うことで、関数がより柔軟で使いやすくなるのが分かりますね。
Rustの関数で戻り値(返り値)を使う
引数が関数への「入力」だとすれば、戻り値(もどりち)または返り値(かえりち)は関数からの「出力」です。
関数が行った処理の結果(例えば計算結果など)を、呼び出した側で受け取って使いたい場合があります。そんな時、関数に結果を返してもらう仕組みが戻り値です。
戻り値を持つ関数を定義するには、`()` の後に `->` と戻り値の型を書きます。
// 2つの i32 型の引数を受け取り、合計値を i32 型で返す関数 fn add(num1: i32, num2: i32) -> i32 { // 関数の最後に評価される式が、暗黙的に戻り値になる num1 + num2 // セミコロンをつけない! } fn main() { // add関数を呼び出し、戻り値を `result` 変数に格納する let result = add(10, 5); println!("計算結果は {} です。", result); // result の中身は 15 }
この `add` 関数は、`num1` と `num2` を足し合わせた結果を `i32` 型の値として返します。注目してほしいのは、`num1 + num2` の行の最後にセミコロン `;` がないことです。
Rustでは、関数のブロック `{}` の中で最後に評価された式(セミコロンがないもの)が、その関数の戻り値になります。これはRustのちょっと面白い特徴です。
もちろん、`return` キーワードを使って明示的に値を返すこともできます。
fn add_explicit(num1: i32, num2: i32) -> i32 { // return キーワードで明示的に返すこともできる return num1 + num2; // この場合、セミコロンが必要 }
どちらの書き方でも同じ結果になりますが、Rustでは最後の式で返す書き方がよく使われます。
戻り値あり関数の定義と呼び出し例
戻り値のイメージを掴むために、もう一つ例を見てみましょう。名前(文字列)を受け取って、挨拶メッセージ(文字列)を返す関数です。
// String 型の引数を受け取り、挨拶文を String 型で返す関数 fn create_greeting(name: String) -> String { // format! マクロを使って文字列を組み立て、それを返す format!("やあ、{}!元気かい?", name) // セミコロンなし } fn main() { // create_greeting 関数を呼び出し、戻り値(挨拶文)を受け取る let tanaka_greeting = create_greeting("田中".to_string()); let suzuki_greeting = create_greeting("鈴木".to_string()); // 受け取った戻り値を出力する println!("{}", tanaka_greeting); println!("{}", suzuki_greeting); }
実行結果
やあ、田中!元気かい? やあ、鈴木!元気かい?
この例では、`create_greeting` 関数が挨拶文という「結果」を作り出して、それを呼び出し元の `main` 関数に返しています。`main` 関数は、その返ってきた結果(文字列)を `tanaka_greeting` や `suzuki_greeting` という変数に格納して、後で表示していますね。
このように、戻り値を使うと関数の処理結果を他の場所で再利用できるのが便利です。
【実践】Rustの関数を使ったサンプルプログラム
さて、これまで学んだ関数の定義、引数、戻り値を組み合わせて、少しだけ実用的なプログラムを書いてみましょう。
ここでは、長方形の幅(width)と高さ(height)を受け取って、その面積(area)と周の長さ(perimeter)を計算して表示するプログラムを作ります。面積計算と周の長さ計算を、それぞれ別の関数に分けてみましょう。
// 長方形の面積を計算して返す関数 fn calculate_area(width: u32, height: u32) -> u32 { width * height // 幅 * 高さ } // 長方形の周の長さを計算して返す関数 fn calculate_perimeter(width: u32, height: u32) -> u32 { (width + height) * 2 // (幅 + 高さ) * 2 } // メインの処理を行う関数 fn main() { let rect_width = 10; let rect_height = 5; // 面積計算関数を呼び出し、結果を受け取る let area = calculate_area(rect_width, rect_height); // 周の長さ計算関数を呼び出し、結果を受け取る let perimeter = calculate_perimeter(rect_width, rect_height); println!("長方形の幅: {}", rect_width); println!("長方形の高さ: {}", rect_height); println!("面積: {}", area); println!("周の長さ: {}", perimeter); }
これを実行すると、以下の結果が表示されます。
長方形の幅: 10 長方形の高さ: 5 面積: 50 周の長さ: 30
どうでしょうか? 面積を計算する処理と、周の長さを計算する処理が、それぞれ独立した関数(部品)になっているのが分かりますか?
サンプルコード解説
上のサンプルコードの流れを追いかけてみましょう。
- `calculate_area` 関数の定義
幅 `width` と高さ `height`(どちらも `u32` 型=符号なし32ビット整数)を引数として受け取り、掛け合わせた結果(面積)を `u32` 型で返します。`width * height` が最後の式なので、これが戻り値になります。 - `calculate_perimeter` 関数の定義
同じく幅 `width` と高さ `height` を引数に受け取り、`(width + height) * 2` で計算した周の長さを `u32` 型で返します。 - `main` 関数の実行開始
プログラムは `main` 関数から始まります。 - 変数の準備
`rect_width` に 10、`rect_height` に 5 を代入します。これが計算の材料になります。 - 面積の計算と結果の格納
`calculate_area` 関数を `rect_width` と `rect_height` を引数にして呼び出します。関数は 10 * 5 = 50 を計算し、その結果(戻り値)を返します。返ってきた 50 が `area` という変数に格納されます。ここで関数の「戻り値」が活躍していますね! - 周の長さの計算と結果の格納
同様に `calculate_perimeter` 関数を呼び出します。(10 + 5) * 2 = 30 が計算され、その結果が `perimeter` 変数に格納されます。 - 結果の表示
最後に、準備した値や関数から受け取った結果を `println!` を使って表示します。
このように、特定の計算や処理を関数として切り出すことで、`main` 関数の中身がスッキリし、「何をしようとしているか」が分かりやすくなります。これが関数を使う大きなメリットの一つです。
Rustの関数を使う上での注意点
Rustの関数を使う上で、初心者のうちにつまずきやすい点や、知っておくと良いことをいくつか挙げておきますね。
型指定は必須!
関数の引数と戻り値には、必ず型を指定する必要があります。`fn add(num1, num2)` のように型を省略することはできません。命名規則はスネークケースで
関数名や変数名は、`calculate_total_score` のように、小文字のアルファベットをアンダースコア `_` でつなぐ「スネークケース」で書くのがRustコミュニティの慣習です。読みやすいコードを書くためにも、この慣習に従うのがおすすめです。式と文の違い(セミコロンの有無)
Rustでは、セミコロン `;` が付いている行は「文(Statement)」、付いていない行は「式(Expression)」として扱われることがあります。fn returns_five() -> i32 { 5 // 式: セミコロンなし。これが戻り値になる } fn does_not_return() { let x = 5; // 文: セミコロンあり。値は返さない }
最初は少し戸惑うかもしれませんが、コードを書きながら徐々に慣れていきましょう!
【まとめ】Rustの関数を使いこなしてステップアップ!
今回はRustの関数について、基本から一歩進んだ使い方までを見てきました。
ポイントをまとめると…
- 関数は、処理をまとめた部品。
- `fn 関数名()` `{ 処理 }` で定義する。
- `関数名()` で呼び出す。
- 引数を使うと、関数に情報を渡せる。(`fn func(arg: Type)`)
- 戻り値を使うと、関数から結果を受け取れる。(`fn func() -> Type`)
- 関数を使うと、コードが整理され、読みやすく、再利用しやすくなる!
関数は、どんなプログラミング言語でも登場する基本的な要素です。Rustの関数をしっかり理解し、使いこなせるようになれば、もっと複雑で面白いプログラムも作れるようになりますよ。
今回学んだことを活かして、ぜひ自分の手で色々な関数を作ってみてください。コードを書けば書くほど、関数と仲良くなれるはずです。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。