概要

メソッドは、よく使用する処理を手軽に実行することができるものである。

メソッドを呼び出すには、数値や文字列などの任意の引数を用意して実行する。
そして、実行した結果を戻り値として返す。
このメソッドの結果を、他の処理や演算に利用することもできる。

Rustには、標準ライブラリに多くのメソッドが用意されている。
Rustの標準ライブラリは、Rustの公式Webサイト で確認することができる。


メソッド

メソッドの定義

メソッドを作成するには関数名が必要である。
Rustのメソッド名は、スネークケースで記述するのが慣習である。

  • 小文字の英字 (a-z)
  • 数字 (0-9)
    ※ただし、関数の先頭文字としては使用できない。
  • アンダースコア (_)


関数の作成

関数を定義するには、fn キーワードを使用する。

fnに続けて関数名を記述した後、丸括弧()を記述する。
丸括弧()の中には引数の定義を入れる場合もある。

戻り値の型がある場合は、-> に続けて型を指定する。
関数本体は波括弧 {} で囲む。

 fn 関数名([引数名: , ...]) [-> 戻り値の型] {
    実行コード
 }


以下の例では、Hello!と出力するsay_hello関数である。

 fn say_hello() {
    println!("Hello!");
 }
 
 fn main() {
    say_hello();
 }
 
 // 出力
 Hello!


上記のsay_hello関数を変更して、引数に名前を入れてHello! <名前>を出力するメソッドを定義する。

 fn say_hello(name: &str) {
    println!("Hello! {}", name);
 }
 
 fn main() {
    say_hello("Rust");
 }
 
 // 出力
 Hello! Rust


標準ライブラリの関数の使用

標準ライブラリの関数を使用するには、関数名に丸括弧 () を付けて呼び出す。

 fn main() {
    let s = "Rust";
    println!("{}", s.len());
 }
 
 // 出力
 4


※注意
Rustでは、全ての関数の引数と戻り値の型を明示的に指定する必要がある。
メソッド名は、スネークケースで記述するのが慣習である。


引数

位置引数

メソッドの引数は複数指定できる。

引数は位置によって対応付けられ、呼び出し時に順番通りに渡される。
全ての引数には型を明示的に指定する必要がある。

 fn dinner_menu(food: &str, drink: &str, dessert: &str) {
    println!("夕食は{}を用意しています。", food);
    println!("飲み物は{}をおすすめします。", drink);
    println!("デザートに{}をどうぞ。", dessert);
 }
 
 fn main() {
    dinner_menu("定食", "お茶", "ゼリー");
 }
 
 // 出力
 夕食は定食を用意しています。
 飲み物はお茶をおすすめします。
 デザートにゼリーをどうぞ。


※注意
Rustには、キーワード引数の機能はない。
引数は常に位置によって対応付けられる。

デフォルト引数

Rustには、デフォルト引数の機能は存在しない。
しかし、Option型やメソッドのオーバーロードの代替として、複数のメソッドを定義することで同様の効果を得ることができる。

以下の例では、Option型を使用してデフォルト値を実現している。

 fn dinner_menu(food: Option<&str>, drink: Option<&str>, dessert: Option<&str>) {
    let food = food.unwrap_or("定食");
    let drink = drink.unwrap_or("お茶");
    let dessert = dessert.unwrap_or("ゼリー");
 
    println!("夕食は{}を用意しています。", food);
    println!("飲み物は{}をおすすめします。", drink);
    println!("デザートに{}をどうぞ。", dessert);
 }
 
 fn main() {
    // 全てデフォルト値を使用
    dinner_menu(None, None, None);
 
    // 一部を指定
    dinner_menu(Some("ハンバーグ"), Some("赤ワイン"), Some("シャーベット"));
 }
 
 // 出力
 夕食は定食を用意しています。
 飲み物はお茶をおすすめします。
 デザートにゼリーをどうぞ。
 夕食はハンバーグを用意しています。
 飲み物は赤ワインをおすすめします。
 デザートにシャーベットをどうぞ。


あるいは、ビルダーパターンを使用する方法もある。

 struct DinnerMenu {
    food: String,
    drink: String,
    dessert: String,
 }
 
 impl DinnerMenu {
    fn new() -> Self {
       DinnerMenu {
          food: "定食".to_string(),
          drink: "お茶".to_string(),
          dessert: "ゼリー".to_string(),
       }
    }
 
    fn food(mut self, food: &str) -> Self {
       self.food = food.to_string();
       self
    }
 
    fn drink(mut self, drink: &str) -> Self {
       self.drink = drink.to_string();
       self
    }
 
    fn dessert(mut self, dessert: &str) -> Self {
       self.dessert = dessert.to_string();
       self
    }
 
    fn show(&self) {
       println!("夕食は{}を用意しています。", self.food);
       println!("飲み物は{}をおすすめします。", self.drink);
       println!("デザートに{}をどうぞ。", self.dessert);
    }
 }
 
 fn main() {
    // デフォルト値を使用
    DinnerMenu::new().show();
 
    // 一部を変更
    DinnerMenu::new()
       .food("ハンバーグ")
       .drink("赤ワイン")
       .show();
 }



可変長引数

Rustには、組み込みの可変長引数の機能は存在しない。
しかし、スライス、ベクター、マクロを使用することにより、同様の効果を得ることができる。

スライスを使用した可変長引数

以下の例では、スライスを引数として受け取ることで、複数の値を処理している。

 fn dinner_menu(items: &[&str]) {
    for item in items {
       println!("{}", item);
    }
 }
 
 fn main() {
    let menu = ["定食", "お茶", "ゼリー"];
    dinner_menu(&menu);
 }
 
 // 出力
 定食
 お茶
 ゼリー


ベクタを使用した可変長引数

以下の例では、ベクタを使用して可変長の引数を実現している。

 fn dinner_menu(items: Vec<String>) {
    for item in items {
       println!("{}", item);
    }
 }
 
 fn main() {
    let menu = vec!["定食".to_string(), "お茶".to_string(), "ゼリー".to_string()];
    dinner_menu(menu);
 }
 
 // 出力
 定食
 お茶
 ゼリー


マクロを使用した可変長引数

マクロを使用すると、より柔軟な可変長引数を実現できる。

 macro_rules! print_items {
    ($($item:expr),*) => {
       $(
          println!("{}", $item);
       )*
    };
 }
 
 fn main() {
    print_items!("定食", "お茶", "ゼリー");
 }
 
 // 出力
 定食
 お茶
 ゼリー



関数ポインタとクロージャ

Rustでは、メソッドを変数に代入したり、メソッドの引数として関数を渡したり、メソッドの戻り値として関数を返すことができる。
これには関数ポインタやクロージャを使用する。

関数ポインタ

以下の例では、関数を引数として別の関数に渡している。

 fn hello() {
    println!("Hello, Rust");
 }
 
 fn callback_func(callback: fn()) {
    callback();
 }
 
 fn main() {
    callback_func(hello);
 }
 
 // 出力
 Hello, Rust


クロージャ

クロージャは、無名関数であり、変数に代入したり、引数として渡すことができる。

 fn main() {
    let hello = || {
       println!("Hello, Rust");
    };
 
    let callback_func = |callback: fn()| {
       callback();
    };
 
    callback_func(|| println!("Hello, Rust"));
 }
 
 // 出力
 Hello, Rust



関数内関数 (ネストした関数)

Rustでは、メソッドの中で別のメソッドを定義することができる。

以下の例では、外側のメソッドとその中で定義される内側のメソッドを定義する。
ここでは、外側のメソッド名をouter_func、内側のメソッド名をinner_funcとする。

外側のメソッドでは、2つの引数を加算して、内側のメソッドでは、2つの引数を加えて10倍して、それを出力している。

 fn outer_func(a: i32, b: i32) {
    fn inner_func(c: i32, d: i32) -> i32 {
       (c + d) * 10
    }
 
    let out_value = a + b;
    let in_value = inner_func(a, b);
 
    println!("{} {} OutValue = {} InValue = {}", a, b, out_value, in_value);
 }
 
 fn main() {
    outer_func(3, 4);
 }
 
 // 出力
 3 4 OutValue = 7 InValue = 70


※注意
内側の関数は、外側の関数のスコープ内でのみ使用できる。
内側の関数は、外側の関数の変数にアクセスできない。(クロージャを使用すればアクセス可能)