我可以在运行时选择特征对象而不使用Box <trait>?</trait>

时间:2015-02-01 15:28:04

标签: rust lifetime

我想分支并决定在运行时在函数中使用的Trait实现(请参阅下面的代码示例中的poly_read)。 trait对象是在if表达式的分支臂内部构造的,只需要在poly_read的生命中存活但我需要Box它因为该特征不能从表达式中借用手臂,直到我试图分配它的绑定。

我从逻辑上理解为什么借款过早结束,但似乎借用检查器应该能够在if表达式的值绑定时将借用扩展到周围的范围。我意识到这可能是一个天真的想法,但我想更多地了解为什么它不可能。

我对我现在的解决方案有点不满意,因为它需要堆分配,即使我觉得我不需要堆分配,因为我只保留了该功能的生命周期。我想这是因为我们不知道在采用分支之前堆栈上需要的reader的大小,但是它不能仅仅在编译器中表示为联合,因为我们至少知道最大尺寸。

顺便说一句,我实际上不知道我对所分配的Box堆的关注是多么有效。一般来说,装箱价值有多贵?

#![feature(io)]
#![feature(path)]

const BYTES: &'static [u8] = &[1u8, 2, 3, 4, 5];
const PATH: &'static str = "/usr/share/dict/words";

use std::old_io::{File, Reader, BufReader};


fn read(r: &mut Reader) {
    let some_bytes = r.read_exact(5).unwrap();
    assert!(some_bytes.len() == 5);
    println!("{:?}", some_bytes);
}

fn poly_read(from_file: bool) {
    // Is there any way to extend the lifetime of the ``&mut Reader`` in these branch arms without
    // boxing them as I'm doing now. It seems wasteful to do a heap allocation when the actual
    // borrow only needs to happen for body of poly_read?
    let mut reader = if from_file {
        Box::new(File::open(&Path::new(PATH)).unwrap()) as Box<Reader>
        // Would like to say:
        // File::open(&Path::new(FILE)).unwrap() as &mut Reader
    } else {
        Box::new(BufReader::new(BYTES)) as Box<Reader>
        // Would like to say:
        // BufReader::new(BYTES) as &mut Reader
    };
    // It feels like I'd like the lifetime of values returned from if expressions to be of the
    // surrounding scope, rather than the branch arms.
    read(&mut reader);
}

fn main() {
    poly_read(true);
    poly_read(false);
}

1 个答案:

答案 0 :(得分:1)

正如@Shepmaster所指出的那样,有一种方法与this answer中的previous question类似。

解决此问题的方法是预先声明两个必要变量:FileBufReader

fn poly_read(from_file: bool) {
    // These two variables are predeclared so that they are in scope as
    // long as `reader` is
    let mut file_reader;
    let mut buf_reader;

    let mut reader = if from_file {
        file_reader = File::open(&Path::new(PATH)).unwrap();
        &mut file_reader as &mut Reader
    } else {
        buf_reader = BufReader::new(BYTES);
        &mut buf_reader as &mut Reader
    };

    read(&mut reader);
}

另见this code on the Rust playpen.