blog.dopana

Back

Rust入門シリーズの第4回です。関数はロジックに名前を付け、再利用するための方法です。Rustの関数はシンプルです — 核となる考えは、ほぼすべてが式だということです。

最初の関数#

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let result = add(3, 4);
    println!("{result}");   // 7
}
rust

パラメータは型を宣言し、戻り値の型は->の後に置きます。

ステートメントと式#

ステートメントは動作を実行し、何も返しません。式は値を評価します。

fn add(a: i32, b: i32) -> i32 {
    let sum = a + b;   // ステートメント、セミコロンで終わる
    sum                // 式、セミコロンなし
}
rust

最後の式 — セミコロンなし — が戻り値になります。セミコロンを付けると、関数は代わりに()を返します。

早期リターン#

returnで早期に抜けます:

fn is_adult(age: u32) -> bool {
    if age >= 18 {
        return true;
    }
    false
}
rust

戻り値がない関数#

何も返さない関数はユニット型()を持ちます:

fn greet(name: &str) {
    println!("Hello, {name}!");
}
rust

暗黙の戻り値の型は()です。

所有権の受け渡し#

デフォルトでは、値を関数に渡すと移動します(詳細は次回の所有権の記事):

fn print_len(s: String) {
    println!("{}", s.len());
}

fn main() {
    let s = String::from("hello");
    print_len(s);   // sが移動される
    // println!("{s}");  // エラー: sはもう存在しない
}
rust

ジェネリック関数#

関数は山括弧を使って型に対してジェネリックにできます:

fn first<T>(list: &[T]) -> &T {
    &list[0]
}
rust

Tは任意の型を表します。コンパイラが呼び出し箇所から推論します。

結論#

Rustの関数はどこまでも式です。パラメータは型付けされ、最後の式が戻り値になり、所有権は値とともに移動します。シリーズ次回は所有権です。

参考文献#