如何创建可动态生成值并返回其借用的Factory结构体?
问题描述
我需要一个名为Factory的结构体,它要能动态生成新的String,将这些字符串存储在内部,并且返回与Factory自身生命周期一致的&str借用。
我曾尝试用Vec存储这些新值,但Vec扩容时元素的借用会失效,导致生命周期不足;也试过用Box、RefCell包装,还是遇到同样的问题。另外,我希望能在循环中调用该工厂的方法,每次迭代生成新的String并保留其借用。
解决方案
有一个string-interner crate,如果你的需求只是获取字符串句柄,直接使用它或者参考下面的类似结构体实现都是不错的选择。
针对String的实现
use std::{cell::{Ref, RefCell}, rc::Rc}; struct StringHandle { key: usize, store: Rc<RefCell<Vec<String>>>, } impl StringHandle { pub fn get(&self) -> Ref<String> { Ref::map(self.store.borrow(), |v| &v[self.key]) } } struct Factory { pub store: Rc<RefCell<Vec<String>>>, } impl Factory { pub fn make_next_string(&mut self) -> StringHandle { let len = self.store.borrow().len(); self.store.borrow_mut().push(format!("string no. {}", len)); StringHandle { store: self.store.clone(), key: len, } } pub fn new() -> Factory { Factory { store: Rc::new(RefCell::new(vec![])) } } } let mut f = Factory::new(); let mut strs: Vec<StringHandle> = vec![]; for _ in 0..5 { let handle = f.make_next_string(); strs.push(handle); } for handle in strs { println!("{}", handle.get()); }
适用于任意结构体的泛型版本
use std::{cell::{Ref, RefCell, RefMut}, rc::Rc}; struct Handle<T> { key: usize, store: Rc<RefCell<Vec<T>>>, } impl<T> Handle<T> { pub fn get(&self) -> Ref<T> { Ref::map(self.store.borrow(), |v| &v[self.key]) } pub fn get_mut(&self) -> RefMut<T> { RefMut::map(self.store.borrow_mut(), |v| &mut v[self.key]) } } struct Factory<T> { pub store: Rc<RefCell<Vec<T>>>, } impl<T: Default> Factory<T> { pub fn make_next(&mut self) -> Handle<T> { let len = self.store.borrow().len(); self.store.borrow_mut().push(T::default()); Handle { store: self.store.clone(), key: len, } } pub fn new() -> Factory<T> { Factory { store: Rc::new(RefCell::new(vec![])) } } } #[derive(Debug)] struct Data { pub number: i32 } impl Default for Data { fn default() -> Self { Data { number: 0 } } } let mut objs: Vec<Handle<Data>> = vec![]; let mut f: Factory<Data> = Factory::new(); for i in 0..5 { let handle = f.make_next(); handle.get_mut().number = i; objs.push(handle); } for handle in objs { println!("{:?}", handle.get()); }
内容的提问来源于stack exchange,提问作者Kamil Szot
相关产品推荐
相关产品推荐

