`Rc`,`Box`,`Arc`的常规指针类型

Kap*_*chu 5 rust

我有一个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)

(is.gd/qUkAvZ)

可能的解决方案: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.

Fra*_*gné 5

虽然Deref提供了必要的功能,AsRef并且Borrow更适合这种情况(比结构体的情况Borrow更适合)。AsRef这两个特征都允许您的用户使用Box<T>Rc<T>Arc<T>Borrow也允许他们使用&TT。你的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)