参照周りの話
可変参照に対してメソッドを呼ぶとき
Section titled “可変参照に対してメソッドを呼ぶとき”String型の変数に対して、push_strメソッドを呼ぶことができる。
fn main() { let mut s = String::from("Hello"); s.push_str("World"); println!("{}", s);}可変参照を使うと次のようにも書ける。
fn main() { let mut s = String::from("Hello"); let r = &mut s; r.push_str("World"); println!("{}", r);}ここで疑問なのが、push_strメソッドはString型で実装されているので、参照型に対する挙動がどうなっているのか、ということである。
push_strの実装
Section titled “push_strの実装”push_strの実装は以下のようになっている。
pub fn push_str(&mut self, string: &str) { self.vec.extend_from_slice(string.as_bytes())}つまりおおざっぱに書くとこんな感じになっている。
impl String { fn push_str(&mut self, string: &str) { ... }}push_strは、&mut selfを受け取るメソッドとなっている。
&mut selfの概念はまだ出てきていないのでわからないが、おそらく、「可変参照を通して自分自身を引数に取る」ということを意味している。
ChatGPTによると、Rustのメソッド呼び出し糖衣構文と言うらしく、mut s: Stringの変数に対しては、自動で&mut sが渡されるらしい。
何にせよ、push_strはString型で実装されているものであるので、some_string: &mut Stringに対して、some_string.push_str()と呼び出したときの挙動については別の話になる。
参照型についてこのメソッドを呼ぶ際には、参照外し (deref) が自動的に行われる。 Rustでは、「参照に外してメソッドを呼ぶ」とき、自動で参照外しして本体にアクセスする。
つまり、&mut String -> Stringへと自動的に参照外し:*が適用される。
そのため実際には、
(*some_string).push_str("World");と同じ意味になり、可変なString変数が渡されるようになる。