PAYATHON 2026

Rust 如何无克隆地将 Box<[T]> 的剩余元素移入新切片?

数据小陈

可以先将 Box<[T]> 转成 Vec<T>,再调用 split_off 取出从索引 idx 开始的元素,最后把结果转回 Box<[T]>。整个过程会移动元素,不需要 T: Clone。

实现

fn split_and_move<T>(source: Box<[T]>, idx: usize) -> Result<Box<[T]>, Box<[T]>> {
    if idx >= source.len() {
        return Err(source);
    }

    let mut values = Vec::from(source);
    let remaining = values.split_off(idx);
    Ok(remaining.into_boxed_slice())
}

为什么不需要克隆

Vec::from(source) 会接管原 Box<[T]> 的所有权。调用 split_off(idx) 后,从索引 idx 开始的元素会移到新的 Vec 中,原来的 Vec 则保留前缀。最后,into_boxed_slice() 将新 Vec 转成返回值。

这段实现只在 idx < source.len() 时执行拆分;当 idx == source.len() 时,会按现有逻辑返回 Err(source)。即使类型没有实现 Clone,也可以这样使用:

struct Item(String);

let items: Box<[Item]> = vec![Item("a".into()), Item("b".into())].into_boxed_slice();
let tail = split_and_move(items, 1).unwrap();

拆出的元素由 tail 持有。原来的 box 已被消费,前缀容器随后释放时,其中的元素会正常析构,返回的切片仍可使用。

注意事项

split_off 需要为拆出的部分创建存储,并移动其中的元素。因此,不克隆 T 不代表完全没有分配或内存操作。如果希望 idx == len 时返回空切片而不是错误,可以将边界判断改为 idx > source.len()。

备注:内容仅供参考。