メソッド
データに対して.関数名()
で呼び出せる関数のことです。.
の左に書いたデータが第1引数となります。
関数を続けて適用する場合に入れ子にすることなく記述できます。
また、開発環境によっては.
をタイプした時点でメソッドの候補が出るためコーディングが非常に楽になります。
fn main() {
// 文字列を整数に変換。parseは失敗する可能性があるメソッドなのでエラー処理が必要。
// unwrap()はエラーの場合panicになる。エラーでなければ値を取り出す。
let mut number: i32 = "3".parse().unwrap();
// i32型はpowメソッドを呼び出すことができる。
number = number.pow(2); // numberを2乗する
println!("3の2乗は {} です。", number);
// まとめて書いてもメソッド構文なら読みやすい
// メソッドを続けて書くことをメソッドチェーンと言う
let number: i32 = "3".parse::<i32>().unwrap().pow(2);
println!(
"3の2乗は {} です。1行で計算しました。",
number
);
}
メソッドチェーンとはメソッドの戻り値に対してメソッド呼び出すことです。チェーンのように処理をつなげていくことが出来ます。
2つ目の例ではメソッドを追加したために、何の型のparse()
なのか区別できなくなりました。そのため、::<i32>
と書いて型をコンパイラに教えています。let
文に型を書いたので推論してくれるかなと期待したのですが駄目でした。
メソッドの実装
impl
ブロックを書き、その中でメソッドを実装します。
impl
型名
{
メソッド
メソッド
メソッド
...
}
以下の例ではメソッドチェーンをやってみたかったので各メソッドの引数と戻り値の型をそろえています。
/// パソコン
/// ログインしてパスワードを変更する機能しかない。
struct PC {
login: bool, //認証
password: String, //パスワード
}
impl PC {
// ログインする
fn login(&mut self, password: &str) -> &mut PC {
if self.password == password {
println!("ログインしました。");
self.login = true;
self
} else {
println!("パスワードが違います");
self
}
}
// ログアウトする
fn logout(&mut self) -> &mut PC {
println!("ログアウトしました。");
self.login = false;
self
}
// パスワード変更
fn change_password(&mut self, new_password: &str) -> &mut PC {
if self.login {
println!("パスワードを変更しました。");
self.password = String::from(new_password);
self
} else {
println!(
"パスワードを変更するにはログインする必要があります。"
);
self
}
}
}
fn main() {
let mut my_pc = PC {
login: false,
password: String::from("abcd"),
};
// ログイン
my_pc.login("abcd");
// パスワード変更
my_pc.change_password("efgh");
// ログアウトしてログインしてパスワード変更してログアウトしてログイン
my_pc
.logout()
.login("efgh")
.change_password("123456789")
.logout()
.login("123456789");
}
余談
implを勉強した素直な感想は「classじゃ無いの?」でした。しかし、理解してみるとこちらのほうが理にかなっている気がします。特に、トレイトとインターフェース(javaなどの)ではトレイトのほうがスマートだと思います。トレイトはこれから勉強する予定なので、javaとの違いを意識してみると面白いかも、などと考えています。