【问题标题】:Initialize boxed slice without clone or copy在没有克隆或复制的情况下初始化盒装切片
【发布时间】:2015-12-15 08:26:10
【问题描述】:

我正在尝试初始化 None 值的盒装切片,以便基础类型 T 不需要实现 CloneCopy。这里有几个理想的解决方案:

fn by_vec<T>() -> Box<[Option<T>]> {
    vec![None; 5].into_boxed_slice()
}

fn by_arr<T>() -> Box<[Option<T>]> {
    Box::new([None; 5])
}

不幸的是,by_vec 实现需要T: Clone,而by_arr 实现需要T: Copy。我尝试了更多方法:

fn by_vec2<T>() -> Box<[Option<T>]> {
    let v = &mut Vec::with_capacity(5);
    for i in 0..v.len() {
        v[i] = None;
    }
    v.into_boxed_slice() // Doesn't work: cannot move out of borrowed content
}

fn by_iter<T>() -> Box<[Option<T>]> {
     (0..5).map(|_| None).collect::<Vec<Option<T>>>().into_boxed_slice()
}

by_vec2 没有通过编译器(我不确定我理解为什么),但by_iter 可以。我担心collect 的性能——它是否需要在迭代时调整它正在收集的向量的大小,或者它是否可以分配正确大小的向量?

也许我做错了——我对 Rust 很陌生,所以任何提示都将不胜感激!

【问题讨论】:

    标签: rust


    【解决方案1】:

    让我们从by_vec2 开始。您将 &amp;mut 引用到 Vec。您不应该这样做,直接使用 Vec 并使 v 绑定可变。

    然后,您将遍历容量为 5、长度为 0 的 Vec 的长度。这意味着您的循环永远不会被执行。你想要的是迭代0..v.cap()

    由于您的 v 的长度仍为 0,因此在循环中访问 v[i] 将在运行时出现恐慌。你真正想要的是v.push(None)。这通常会导致重新分配,但在您的情况下,您已经分配了Vec::with_capacity,因此推送 5 次不会分配。

    这一次我们没有引用Vec,所以into_boxed_slice 确实有效。

    fn by_vec2<T>() -> Box<[Option<T>]> {
        let mut v = Vec::with_capacity(5);
        for _ in 0..v.capacity() {
            v.push(None);
        }
        v.into_boxed_slice()
    }
    

    您的by_iter 函数实际上只分配一次。 0..5 创建的 Range 迭代器知道它正好是 5 个元素长。所以collect 实际上会检查那个长度并且只分配一次。

    【讨论】:

    • 我认为这里最重要的是 Range 迭代器 [...] 知道它正好是 5 个元素的长度。这就是我编写此代码的方式,尽管我会在 collect 类型参数上使用类型推断:(0..5).map(|_| None).collect::&lt;Vec&lt;_&gt;&gt;().into_boxed_slice()
    猜你喜欢
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 2018-04-05
    • 2012-07-27
    • 2011-10-08
    相关资源
    最近更新 更多