コレクションを動的借用する場合の定石について。
コレクションからイテレータを取得して impl Iterator<Item = &T> のように抽象化すると、コレクションそのものを扱うよりも汎用性が高くなる。
上記の技法はそのままでは動的借用されたコレクションでは使えない。なぜなら、イテレータは一般的にコレクションから借用されるのでなく生成される。そのため、コレクション経由のイテレータの借用は不可能である。つまり、動的借用されるコレクションからイテレータを動的借用する事もできない。
コレクションに AsIterator トレイトを導入し、そこからイテレータを生成するとよい。
以下では、動的借用の例として RefCell<T> を使用している。
(RwLock<T> や Mutex<T> でも同様の解決方法が適用可能。)
use std::cell::{Ref, RefCell};
fn main() {
let var = SomeType::new("test".to_string(), vec![1, 2, 3]);
assert_eq!(var.id(), "test");
assert!(var.values().iter().eq(vec![1, 2, 3].iter()));
}
struct SomeType(RefCell<SomeInfo>);
impl SomeType {
fn new(id: String, values: Vec<i32>) -> Self {
Self(RefCell::new(SomeInfo { id, values }))
}
fn id(&self) -> String {
self.0.borrow().id.to_string()
}
fn values(&self) -> Ref<'_, impl AsIterator<Item = i32>> {
Ref::map(self.0.borrow(), |x| &x.values)
}
}
struct SomeInfo {
id: String,
values: Vec<i32>,
}
trait AsIterator {
type Item;
fn iter(&self) -> impl Iterator<Item = &Self::Item>;
}
impl<T> AsIterator for Vec<T> {
type Item = T;
fn iter(&self) -> impl Iterator<Item = &Self::Item> {
<[T]>::iter(&self)
}
}