在Rust枚举/结构中同时接受slice和Vec

时间:2019-06-28 05:26:37

标签: vector rust slice

我有一些与此类似的代码

enum Value<'a> {
    Int(i64),
    Flt(f64),
    Vec(&'a [Value<'a>]),
}

这使我可以重用一些数据;但是,有时候我想接受堆分配的数据,所以我需要像这样的东西

enum Value {
   Int(i64),
   Flt(f64),
   Vec(Box<Vec<Value>>),
}

但是现在我不能接受切片!我知道我总是可以将它们都放在同一个枚举中,

enum Value<'a> {
   Int(i64),
   Flt(f64),
   VecSlice(&'a [Value<'a>]),
   VecBox(Box<Vec<Value<'a>>>),
}

但这很丑。

是否有一种方法可以使结构或枚举在同一成员/变量中同时接受切片和向量?

我知道,对于接受&str和String的函数,我们可以将参数设置为类似T: Into<String>的方式,但是我还没有弄清楚如何对数据类型内部的矢量进行类似的处理。

2 个答案:

答案 0 :(得分:2)

您想要的是Cow

enum Value<'a> {
    Int (i64),
    Flt (f64),
    Vec (Cow<'a, [Value<'a>]>),
}

不幸的是,由于#38962,这不起作用。在解决该问题之前,您可能需要为Cow重新实现Value的专用版本:

enum MyCow<'a> {
    Borrowed (&'a[Value<'a>]),
    Owned (Vec<Value<'a>>)
}

impl<'a> Deref for MyCow<'a> {
    type Target = [Value<'a>];
    fn deref (&self) -> &[Value<'a>] {
        use crate::MyCow::{ Borrowed, Owned };
        match *self {
            Borrowed (borrowed) => borrowed,
            Owned (ref owned) => &owned,
        }
    }
}

playground

答案 1 :(得分:1)

认为最接近您想要的是AsRef特性。值得注意的是,Vec<T>的{​​{1}},[T][T;n]实现了n <= 32,还有其他一些事情(例如切片上的迭代器)也是如此。此外,AsRef<[T]>实现了Box<T>,但是您的AsRef<T>场景在这里无法正常工作。不过,该枚举有点毛茸茸。类型说明不能完全起作用:

Box<Vec<T>>

因为您承诺一次只实例化一个enum Value<S> where S: AsRef<[Value<S>]> { Int(i64), Flt(f64), Slice(S), } ,并且要解决此问题,需要使用S使其异构,这会变得很混乱。

如果您可以重构以使其在功能级别上起作用或在Box<dyn S>之上创建更高级别的类型,则可以具有类似功能

Value

但是,使用此结构相当容易。在这种情况下,如果您有fn foo<S>(slice: S) where S: AsRef<[Value]> { } ,则调用Box<Vec<Value>>不会有效,但由于foo(my_vec)实现了{{1} }。

Box<[T]>

Playground