0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rustの関数はなぜreturn文を使用しないのか?「式ベースの基本」

Posted at

式ベースとは

結論から言うと「式が値を返す」です。
Rustは関数型(主にHaskell)の便利な機能を多く取り入れているので、式ベースや機能で大きな恩恵を受けます。
まずは簡単な関数で見てみましょう

fn main() {
    let y = expression_base(10);
    println!("{}",y); //x = 10 * 2でyは20
}

//式ベースは「式が値を返す]ため、returnは不要です
fn expression_base(x: i32) -> i32 {
    x * 2 //最後の式の値がそのまま返る
}

Rustの知らない方がこのコードを見れば、return文がないことに衝撃を受けるはずでしょ。さらに、行末にセミコロンがないことに驚くはずです。「僕も当時は衝撃でした。」
コード見てわかる通りRust関数の最後の式は値で返すためreturn文やセミコロンを付けないのです。
{05C8ED0B-8DD5-4971-995B-912CBCDABA93}.png

もしこのコードに、セミコロンやreturn文を書いてしまうと。

fn main() {
    let y = expression_base(10);
    println!("{}",y); 
}

fn expression_base(x: i32) -> i32 {
   return x * 2;  
}

エラーになると思いきや、正しくコードは動作します。動作する理由は、Rustは関数の場合はreturnと最後の式を両方サポートしているからです。
Rustの書き方は式ベースで値を返す書き方ですが、returnは途中で抜ける時や、エラー処理をする場合などではreturnを採用する場合があります。
具体的には、エラーハンドリング(例外処理)を行う場合などが代表的です。

fn main() {
    let y = expression_base(10);
    println!("{:?}",y); 
}

fn expression_base(x: i32) -> Result<i32, String> {
   if x < 0 {
    return Err("エラー".into());//異常の場合はreturn式でエラーを返します
   }

   Ok(x * 2)//正常の場合は式で返します
}

コードをご覧の通り、気になるところがあります。戻り値がResultと言う文法が使用されています。簡単に説明しますと、Rustでは「成功か失敗」を表すために使用します。
Ok(T) = 成功したときの値
Err(E) = 失敗したときの値
という仕組みです。

補足
Rustでよくコードを書いているとこのような()記号を見ることが多々あります。この記号はユニット型と言い簡単に言うと、「その式が値を返すことはない」ことを示している場合です。
具体的なコードをご覧ください。

fn main() {
    let unit_type: () = not_worth_it();//ユニット型で返すので,unit_typeの型は()
    println!("{:?}",unit_type);
}

fn not_worth_it() {
    println!("Hello");//Rustは値を返さない関数にはユニット型になります
}

実行結果

Hello//Helloはnot_worth_it関数の副作用
()//Helloはnot_worth_it関数の返り値

Rustは副作用の関数の場合はユニット型を返します。
副作用という単語の意味は式ベースにすることによるメリットで説明します。

文ベースとはなにが違うの

対比として文ベースとは、「値を返さない命令文」です。
文ベース言語では、条件分岐やループ処理などの構文も値は返さず、処理の指示のみを行うのが特徴です。
文ベースで有名な言語はCやJavaで、これらの言語は主に文ベースを使用しています。
以下のC言語のコードをご覧ください。

#include <stdio.h>

int main() {
    int y = sentence_based(10);
    printf("%d\n", y);
    return 0;
}

int sentence_based(int x) {
    return x * 2;
}

このコードでは、sentence_based関数が計算を行いreturn文で値を返しています。Cは文ベースの言語のため、x * 2だけでは命令にはならず、returnを使用して、命令文として返す必要があります。
{01EC47BB-2566-4B0C-A9FE-D5EFA4F09BCF}.png

Rustが式ベースを採用した理由

Rustが式ベースなのは、歴史が関係しています。Rustの作者のグレイドン・ホアレ (Graydon Hoare)氏は、言語のデザインに関数型言語の式ベースの構造を取り入れたことです。

式ベースにすることによるメリット

式ベースにする最大のメリットは「副作用を抑えられる」ためです。
副作用とは「関数や式が外部の状態を変えたり、外部に影響を与えることです。」
つまり、計算の結果だけではなく、

  • 変数の値を変更する
  • 画面に出力したりする
  • ファイルを書き換える

なども副作用に含まれます。

副作用の具体例

fn main() {
    let mut x = 5;
    x += 1;// xの値を直接変更する(副作用)
}
fn main() {
    println!("Hello World");// 標準出力への書き込み(副作用)
}
use std::fs;

fn main() -> std::io::Result<()> {
    let content = "新しいファイル内容";
    fs::write("target.txt", content)?; // ファイルへの書き込み(副作用)
    Ok(())
}

日常的にやっていた処理の多くは、実は副作用を含んでいます。式ベースを基本にすることにより「値を連鎖して返す」スタイルが自然になり、状態の変更(副作用)を最小限に抑えられて、テストやデバッグが簡単になるます。

補足
副作用を抑える設計になってるいるプログラミング言語が純粋関数型のHaskellというプログラミング言語です。「めっちゃ難しいらしいです!!」

まとめ

最後まで、見ていただき、ありがとうございます。いかがですか?
Rustの式ベースは以下のような特徴があります。

  • 式で値を返す: 関数の最後の式はそのまま戻り値になります。
  • returnは必須ではない: エラー処理や早期リターンが必要な場合に使用します。
  • 副作用を抑えられる: 式ベースは副作用を抑え、バグを軽減できる可能性がある。

式ベースの概念を理解すると、Rustのコードを読みやすくなります!

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?