Push
それでは、リストに値をプッシュする処理を書いてみましょう。push はリストを変更するため、
&mut self を受け取る必要があります。また、プッシュする i32 も受け取る必要があります。
impl List {
pub fn push(&mut self, elem: i32) {
// TODO
}
}
まず最初に、要素を格納するノードを作る必要があります。
pub fn push(&mut self, elem: i32) {
let new_node = Node {
elem: elem,
next: ?????
};
}
next には何が入るのでしょうか? そう、古いリスト全体です! これを……そのままやってしまえるでしょうか?
impl List {
pub fn push(&mut self, elem: i32) {
let new_node = Node {
elem: elem,
next: self.head,
};
}
}
> cargo build
error[E0507]: cannot move out of borrowed content
--> src/first.rs:19:19
|
19 | next: self.head,
| ^^^^^^^^^ cannot move out of borrowed content
だめでした。Rust が言っていることは正しいのですが、それが具体的に何を意味しているのか、 あるいはどう対処すべきなのかは、確かに明白ではありません。
借用された内容の外へ move することはできません
私たちは self.head フィールドを next に move しようとしていますが、Rust はそれを許してくれません。
そうすると、借用を終えて正当な所有者に「返す」ときに、self が部分的にしか初期化されていない状態になってしまいます。
前にも述べたように、それは &mut でできない唯一のことです。そんなことをするのは非常に失礼ですし、
Rust はとても礼儀正しいのです(信じられないほど危険でもありますが、もちろん Rust が気にしている理由が
それであるはずはありません)。
何かを戻し入れたらどうでしょう? 具体的には、今作っているノードです。
pub fn push(&mut self, elem: i32) {
let new_node = Box::new(Node {
elem: elem,
next: self.head,
});
self.head = Link::More(new_node);
}
> cargo build
error[E0507]: cannot move out of borrowed content
--> src/first.rs:19:19
|
19 | next: self.head,
| ^^^^^^^^^ cannot move out of borrowed content
うまくいきません。原理的には、これは Rust が実際に受け入れることもできそうなものですが、 受け入れてはくれません(さまざまな理由があります – 最も深刻なのは exception safety です)。 Rust にそれがなくなったと気づかれないように head を取り出す何らかの方法が必要です。助言を求めて、 悪名高い Rust ハッカー、インディアナ・ジョーンズに頼ってみましょう。

なるほど、インディーは mem::replace 作戦を提案しています。この非常に便利な関数を使うと、
ある値を別の値で置き換えることによって、借用の中から値を盗み出せます。
まず、ファイルの先頭で std::mem を取り込んで、mem がローカルスコープに入るようにしましょう。
use std::mem;
そして適切に使います。
pub fn push(&mut self, elem: i32) {
let new_node = Box::new(Node {
elem: elem,
next: mem::replace(&mut self.head, Link::Empty),
});
self.head = Link::More(new_node);
}
ここでは、self.head をリストの新しい head で置き換える前に、一時的に Link::Empty で replace しています。
正直に言うと、これはやらなければならないこととしてはかなり残念なものです。
悲しいことに、私たちは(今のところ)そうしなければなりません。
とはいえ、これで push はすべて完了です! たぶん。正直なところ、たぶんテストすべきでしょう。
今のところ、それを行う最も簡単な方法はおそらく pop を書いて、正しい結果を生成することを確認することです。