コンテンツにスキップ

参照周りの話

可変参照に対してメソッドを呼ぶとき

Section titled “可変参照に対してメソッドを呼ぶとき”

String型の変数に対して、push_strメソッドを呼ぶことができる。

main.rs
fn main() {
let mut s = String::from("Hello");
s.push_str("World");
println!("{}", s);
}

可変参照を使うと次のようにも書ける。

main.rs
fn main() {
let mut s = String::from("Hello");
let r = &mut s;
r.push_str("World");
println!("{}", r);
}

ここで疑問なのが、push_strメソッドはString型で実装されているので、参照型に対する挙動がどうなっているのか、ということである。

push_strの実装は以下のようになっている。

string.rs
pub fn push_str(&mut self, string: &str) {
self.vec.extend_from_slice(string.as_bytes())
}

つまりおおざっぱに書くとこんな感じになっている。

string.rs
impl String {
fn push_str(&mut self, string: &str) { ... }
}

push_strは、&mut selfを受け取るメソッドとなっている。

&mut selfの概念はまだ出てきていないのでわからないが、おそらく、「可変参照を通して自分自身を引数に取る」ということを意味している。

ChatGPTによると、Rustのメソッド呼び出し糖衣構文と言うらしく、mut s: Stringの変数に対しては、自動で&mut sが渡されるらしい。

何にせよ、push_strString型で実装されているものであるので、some_string: &mut Stringに対して、some_string.push_str()と呼び出したときの挙動については別の話になる。

参照型についてこのメソッドを呼ぶ際には、参照外し (deref) が自動的に行われる。 Rustでは、「参照に外してメソッドを呼ぶ」とき、自動で参照外しして本体にアクセスする。

つまり、&mut String -> Stringへと自動的に参照外し:*が適用される。 そのため実際には、

(*some_string).push_str("World");

と同じ意味になり、可変なString変数が渡されるようになる。