【问题标题】:Accept both slice and Vec in Rust enum/struct在 Rust 枚举/结构中同时接受 slice 和 Vec
【发布时间】:2019-11-10 02:00:37
【问题描述】:

我有一些类似的代码

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&lt;String&gt; 之类的东西,但我还没有弄清楚如何对数据类型中的向量执行类似的操作。

【问题讨论】:

  • Box&lt;Vec&lt;Value&gt;&gt; 框向量没有意义
  • @Stargateur 好吧,如果枚举中的向量未装箱,则枚举大小将为 32 字节,而不是装箱时的 16 字节。这在某些情况下可能很重要
  • play.integer32.com/…,我没看到你的问题
  • @Stargateur 你是对的!我只是尝试从一个函数返回一个未装箱的向量,一切正常。问题是我没有指定向量的生命周期,因此没有指定Box。谢谢你:)
  • 我不认为 slice 需要胖指针和 enum 也需要一些空间,注意不要太担心,代码,看看是否有问题。

标签: vector rust slice


【解决方案1】:

你要的是Cow:

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

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

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

【讨论】:

  • 似乎有一个workaround 用于使用Cow - 我还没有尝试将它应用到这个案例中。
【解决方案2】:

认为最接近你想要的是AsRef trait。值得注意的是,Vec&lt;T&gt;[T][T;n] for n &lt;= 32 实现了 AsRef&lt;[T]&gt;,就像其他一些事情一样(例如切片上的迭代器)。此外,Box&lt;T&gt; 实现了AsRef&lt;T&gt;,但您的Box&lt;Vec&lt;T&gt;&gt; 方案在这里不太适用。不过,枚举有点毛茸茸。类型描述不太适用:

enum Value<S>
    where S: AsRef<[Value<S>]>
{
    Int(i64),
    Flt(f64),
    Slice(S),
}

因为您致力于一次只实例化一个 S,而修复该问题需要使用 Box&lt;dyn S&gt; 使其异构,这变得非常混乱。

如果您可以重构以使其在函数级别上工作或在Value 之上创建更高级别的类型,您可以拥有类似的函数

fn foo<S>(slice: S) where S: AsRef<[Value]> { }

但是,使用这种结构相当容易。在这种情况下,如果您有 Box&lt;Vec&lt;Value&gt;&gt;,则调用 foo(my_vec) 将不会完全工作,但可以通过取消引用轻松修复,因为 Box&lt;[T]&gt; 实现了 From&lt;Vec&lt;T&gt;&gt;

use std::convert::AsRef;

enum Value
{
    Int(i64),
    Flt(f64),
}

fn main() {
    use Value::*;

    let x = Box::new(vec![Int(5),Flt(22.5),Int(22)]);
    foo(*x)
}

fn foo<S>(slice: S) where S: AsRef<[Value]> {

}

Playground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 2023-01-03
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    相关资源
    最近更新 更多