我有struct
引用一个值(因为它是?Sized
或非常大)。当然,这个值必须与结构一起使用
但是,结构不应该限制用户如何来实现它。无论用户是将值包装在Box
还是Rc
中还是使其成为'static
,该值都必须与结构一起存活。使用命名生命周期会很复杂,因为引用将被移动并且可能比我们的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);
编译,一切都很好。但是如果我们不想使用Box
作为指向我们函数的指针(可以调用Box
一个指针,对吧?),还有别的东西,比如Rc
,这不会是可能的,因为Caller
将指针限制为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);
可能的解决方案: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);
}
这是Rust的方式吗?使用Deref
?它起码至少。
我错过了一些明显的东西吗?
This question无法解决我的问题,因为该值实际上无法用作T
。
答案 0 :(得分:3)
虽然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,
}
然后,当您想要使用callback
字段时,需要调用borrow()
(或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)
}
}
答案 1 :(得分:1)
它与当前稳定的编译器(1.1)崩溃,但不与beta或nightly崩溃(只需使用您的上一个Playypen链接并更改&#34; Channel&#34;设置在顶部)。我认为{1.1}中对Rc<Trait>
的支持仅为 partial ;有一些变化并没有及时实现。这可能是为什么您的代码无法正常工作。
要解决使用Deref
的问题......如果解除引用指针就是你需要的......当然。这真的只是一个问题,即您选择的特征是否支持您需要的操作。如果是的话,很棒。
另外,您总是可以编写一个表达所需 exact 语义的新特征,并为现有类型实现该特征。从你所说的话来看,在这种情况下似乎没有必要。