#rust
#Ржавчина
Вопрос:
У меня есть следующий код, который реализует какую-то отложенную инициализацию, и я хочу использовать внутреннюю изменчивость и реализацию Deref для удобства.
pub struct Deferred<T> {
value: RefCell<Value<T>>
}
pub enum Value<T> {
Initialized(T),
WaitingForValue
}
impl<T> Deferred<T> {
pub fn init_later() -> Self {
Self { value: RefCell::new(WaitingForValue) }
}
pub fn init(amp;self, value: T) {
self.value.replace(Initialized(value));
}
}
impl<T> Deref for Deferred<T> {
type Target = T;
fn deref(amp;self) -> amp;Self::Target {
if let Initialized(value) = self.value.borrow().deref() {
value
} else {
panic!("Deferred value must be initialized before the first usage")
}
}
}
Но у меня ошибка:
error[E0515]: cannot return value referencing temporary value
|
30 | if let Initialized(value) = self.value.borrow().deref() {
| ------------------- temporary value created here
31 | value
| ^^^^^ returns a value referencing data owned by the current function
Я пробовал разные ссылочные типы, но не могу заставить это работать.
Кроме того, я пытался сделать это с помощью unsafe:
fn deref(amp;self) -> amp;Self::Target {
unsafe {
if let Initialized(value) = amp;*self.value.as_ptr() {
amp;value
} else {
panic!("Deferred value must be initialized before the first usage")
}
}
}
В этом случае это работает, но я не уверен, что этот небезопасный код не приводит к неопределенному поведению.
Ответ №1:
Вы не можете вернуть общую ссылку из a RefCell
, потому что проверка заимствования выполняется во время выполнения с помощью Ref
и RefMut
, этой реализации-оболочки as_ref<Inner>
, но созданные ссылки принадлежат оболочке ( Ref
/ RefMut
), поэтому вы должны сохранить их в хранилище.
Это усложняет использование функций deref
и as_ref
, но вы можете добиться такого же поведения, например, внедрив Deref
on Value<T>
вместо Deffered
use std::{cell::{RefCell}, ops::{Deref}};
pub struct Deferred<T> {
value: RefCell<Value<T>>
}
pub enum Value<T> {
Initialized(T),
WaitingForValue
}
impl<T> Deferred<T> {
pub fn init_later() -> Self {
Self { value: RefCell::new(Value::WaitingForValue) }
}
pub fn init(amp;self, value: T) {
self.value.replace(Value::Initialized(value));
}
}
/// Implement deref on `Value` instead of `Deferred`
impl<T> Deref for Value<T> {
type Target = T;
fn deref(amp;self) -> amp;Self::Target {
if let Value::Initialized(value) = self {
value
} else {
panic!("Deferred value must be initialized before a first usage")
}
}
}
fn main() {
let val = Deferred::init_later();
val.init(String::from("Hello, world !"));
let _: amp;String = val.value.borrow().deref();
}