自己参照データ構造を避けよう
code:rs
struct SelfRef {
text: String,
title: Option<&str>,
}
∵ 参照には ライフタイム注釈 が必要で、データ構造全体にもライフタイム注釈が必要となるため しかし、ライフタイム注釈を付与すると、「 所有 したデータとそのデータの 参照」という意図が表現できなくなる ライフタイム注釈を追加すると、SelfRef 構造体は外部の何かを参照していると見なされる
しかし実際には、 title は SelfRef 内部のtext を指しているため
code:rs
let mut s = SelfRef {...}
s.title = Some(&s.text0..5); let s2 = s; // ここでムーブすることで、s のメモリアドレスが変わることがある
一番簡単な回避策: インデックス(text の範囲の オフセット)を使う code:rs
struct SelfRef<'a> {
text: String,
title: Option<std::ops::Range<usize>>,
}
問題点: 整合しなくなる可能性があり、存在しない text の範囲を指すことがある
自己参照データ構造は(意識せずとも) async を扱う際に生じている
コンパイラは async のコードブロックを クロージャ にまとめる クロージャには、コードとそのコードが動作する環境の一部を キャプチャ したものが含まれる キャプチャされた環境には、値そのものと値への参照の双方が含まれる
この 「値そのものと値への参照」が実質自己参照データ構造
したがって、Pin<T> は自己参照データ構造を構築する 1 つの解決策となるが、正しく理解するのが難しいので公式ドキュメントをしっかり読む必要がある
正しく理解するのが難しい
以上を踏まえると、「自己参照データ構造を避ける」か、難しさをカプセル化してくれるクレート(e.g. ouroborous)を探す