如何复制共享切片以具有盒装切片?

 收藏

我有一个容器:

pub struct Foo<T> {
    pub data: Box<[T]>,
}

我想要一种从现有切片初始化新的方法:

impl<T> Foo<T> {
    fn from_slice(slice: &[T]) -> Foo<T> {
        Foo {
            data: Box::new(/* something here */),
        }
    }
}

I'd like to create a Foo instance from any kind of slice, coming from a dynamic vector or a static string.

I suppose there is a reason why vec! is a macro, but is there a way to avoid writing one? I guess I could do slice.to_vec().into_boxed_slice(), but it doesn't seem right to create a Vec as a proxy to a clone...

I'm not using a Vec in my struct because the data isn't supposed to change in size during the lifetime of my container. It didn't feel right to use a Vec but I may be wrong.

回复
  • 婚礼礼堂 回复

    If your slice contains Copy types, you can use From / Into to perform the construction:

    pub struct Foo<T> {
        pub data: Box<[T]>,
    }
    
    impl<T> Foo<T> {
        fn from_slice(slice: &[T]) -> Foo<T>
        where
            T: Copy,
        {
            Foo { data: slice.into() }
        }
    }
    

    If your data is Clone, then you can use to_vec + into_boxed_slice:

    impl<T> Foo<T> {
        fn from_slice(slice: &[T]) -> Foo<T>
        where
            T: Clone,
        {
            Foo { data: slice.to_vec().into_boxed_slice() }
        }
    }
    

    it doesn't seem right to create a Vec as a proxy to a clone

    You aren't cloning here. When you clone a type T, you get a type T back. You are starting with a &[T] and want to get a Box<[T]>, not a [T] (which you can't have).

    Creating a boxed slice through a Vec means that you temporarily take up 3 machine-sized integers instead of 2; this is unlikely to be a performance problem compared to the amount of allocation performed.

    I do agree with starblue's answer that keeping a Vec<T> is probably simpler for most cases, but I admit that there are times where it's useful to have a boxed slice.

    也可以看看:

    I suppose there is a reason why vec! is a macro

    The implementation of vec! is public:

    macro_rules! vec {
        ($elem:expr; $n:expr) => (
            $crate::vec::from_elem($elem, $n)
        );
        ($($x:expr),*) => (
            <[_]>::into_vec(box [$($x),*])
        );
        ($($x:expr,)*) => (vec![$($x),*])
    }
    

    It's really only a macro for syntax convenience (and because it uses the unstable box keyword); it takes the arguments, creates an array, boxes it, coerces it to a boxed slice, then converts it to a Vec.