我有一个struct引用一个值(因为它是?Sized或非常大).当然,这个值必须与结构一起使用.
但是,结构不应该限制用户如何实现它.无论用户是否将值包装在一个Box或者包含Rc它中'static,该值都必须与struct一起生存.使用命名生命周期会很复杂,因为引用将被移动并且可能比我们的生命周期更长struct.我正在寻找的是一般指针类型(如果它存在/可以存在).
只要结构存在,结构如何确保引用的值存在,而不指定如何?
示例(is.gd/Is9Av6):
type CallBack = Fn(f32) -> f32;
struct Caller {
call_back: Box<CallBack>,
}
impl Caller {
fn new(call_back: Box<CallBack>) -> Caller {
Caller {call_back: call_back}
}
fn call(&self, x: f32) -> f32 {
(self.call_back)(x)
}
}
let caller = {
// func goes out of scope
let func = |x| 2.0 * x;
Caller {call_back: Box::new(func)}
};
// func survives because it is referenced through a `Box` in `caller`
let y = caller.call(1.0);
assert_eq!(y, 2.0);
Run Code Online (Sandbox Code Playgroud)
编译,一切都很好.但是如果我们不想使用a Box作为指向我们函数的指针(一个可以调用Box一个指针,对吗?),但是其他东西,比如Rc,这是不可能的,因为Caller将指针限制为a Box.
let caller = {
// function is used by `Caller` and `main()` => shared resource
// solution: `Rc`
let func = Rc::new(|x| 2.0 * x);
let caller = Caller {call_back: func.clone()}; // ERROR Rc != Box
// we also want to use func now
let y = func(3.0);
caller
};
// func survives because it is referenced through a `Box` in `caller`
let y = caller.call(1.0);
assert_eq!(y, 2.0);
Run Code Online (Sandbox Code Playgroud)
可能的解决方案:Deref?(http://is.gd/mmY6QC)
use std::rc::Rc;
use std::ops::Deref;
type CallBack = Fn(f32) -> f32;
struct Caller<T>
where T: Deref<Target = Box<CallBack>> {
call_back: T,
}
impl<T> Caller<T>
where T: Deref<Target = Box<CallBack>> {
fn new(call_back: T) -> Caller<T> {
Caller {call_back: call_back}
}
fn call(&self, x: f32) -> f32 {
(*self.call_back)(x)
}
}
fn main() {
let caller = {
// function is used by `Caller` and `main()` => shared resource
// solution: `Rc`
let func_obj = Box::new(|x: f32| 2.0 * x) as Box<CallBack>;
let func = Rc::new(func_obj);
let caller = Caller::new(func.clone());
// we also want to use func now
let y = func(3.0);
caller
};
// func survives because it is referenced through a `Box` in `caller`
let y = caller.call(1.0);
assert_eq!(y, 2.0);
}
Run Code Online (Sandbox Code Playgroud)
这是Rust的方式吗?用Deref?它起码至少.
我错过了一些明显的东西吗
这个问题没有解决我的问题,因为这个值几乎无法用作T.
虽然Deref提供了必要的功能,AsRef并且Borrow更适合这种情况(比结构体的情况Borrow更适合)。AsRef这两个特征都允许您的用户使用Box<T>、Rc<T>和Arc<T>,Borrow也允许他们使用&T和T。你的Caller结构可以这样写:
use std::borrow::Borrow;
struct Caller<CB: Borrow<Callback>> {
callback: CB,
}
Run Code Online (Sandbox Code Playgroud)
然后,当你想使用该callback字段时,你需要调用borrow()(or as_ref()) 方法:
impl<CB> Caller<CB>
where CB: Borrow<Callback>
{
fn new(callback: CB) -> Caller<CB> {
Caller { callback: callback }
}
fn call(&self, x: f32) -> f32 {
(self.callback.borrow())(x)
}
}
Run Code Online (Sandbox Code Playgroud)