今回は、このサイトに反論していきます。
参照を保存するバッファを再利用できない
これは事実です。いい解決法は今のところありません。
いい解決法ではないですが、解決策としては、下記のように、参照を強制的に引き延ばすことができます。
なお、例えバッファを再利用しても、数回呼び出す程度ならば、その都度イテレータを生成したほうが動作速度は速いでしょう。
pub fn process_sources(sources: Vec<Sources>) {
let mut buffer: Vec<&[u8]> = Vec::new();
for source in sources {
let mut data: Vec<u8> = source.fetch_data();
let data_borrowed = &mut data;
// It's not a smart solution, but everything else has failed.
// You must verify the validity period of the reference yourself.
let data_borrowed: &'_ mut Vec<u8> = unsafe { std::mem::transmute(data_borrowed) };
buffer.extend(data_borrowed.split(splitter));
process_data(buffer.as_ref());
buffer.clear();
}
}
自己参照構造体が作れない
これは、ある程度解決しています。Rustの知識量の問題です。ただし、Cargo miriというメモリ使用診断ツールでは、自己参照構造体はまだエラーが出ます。現在はIssueで話し合った後放置されています。
自己参照構造体は、PinとMaybeUninitを用いると書けます。
例はこんな感じです。理解できない人は自己参照構造体を作れるライブラリなどを使って下さい。
かなり端折っているので、コードをすべて見たい人はhttps://github.com/oligamiq/small_example_lifetime をどうぞ
pub struct PinUninitGuard<'a, T: Unpin + PinnedInit> {
initialized: Pin<&'a mut T>,
}
impl<'a, T: Unpin + PinnedInit> PinUninitGuard<'a, T> {
pub fn new(mut pinned: Pin<&'a mut MaybeUninit<T>>, builder: T::Builder) -> Self {
unsafe { <T as PinnedInit>::init(&mut pinned, builder) };
Self {
initialized: unsafe { pinned.map_unchecked_mut(|t| t.assume_init_mut()) },
}
}
}
impl<'a, T: Unpin + PinnedInit> Drop for PinUninitGuard<'a, T> {
fn drop(&mut self) {
unsafe {
MaybeUninit::assume_init_drop(
core::mem::transmute::<&mut T, &'a mut MaybeUninit<T>>(
&mut self.initialized.as_mut(),
),
)
};
}
}
fn main() {
let normalizer = std::pin::pin!(Normalizer::uninit());
let mut normalizer = PinUninitGuard::new(normalizer, Cache::new());
normalizer.use_something();
normalizer.use_component();
let mut boxed_normalizer = Box::pin(Normalizer::uninit());
let boxed_normalizer = boxed_normalizer.as_mut();
let mut boxed_normalizer = PinUninitGuard::new(boxed_normalizer, Cache::new());
boxed_normalizer.use_something();
boxed_normalizer.use_component();
}
コンパイル時ジェネリクス
これに関しては、Rustの思想の問題です。
もう行っているようですが、素直にマクロを使うのが一番です。
まとめ
皆さんRustを使いましょう