Принять и ломтик и Vec в Rust enum / struct - PullRequest
2 голосов
/ 28 июня 2019

У меня есть код, похожий на этот

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 ]

2 голосов
/ 28 июня 2019

То, что вы хотите, это 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,
        }
    }
}

детская площадка

1 голос
/ 28 июня 2019

I думаю ближайшая вещь к тому, что вы хотите, это черта AsRef. В частности, Vec<T>, [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) не будет вполне работать, но может быть тривиально исправлен с помощью разыменования, поскольку Box<[T]> реализует From<Vec<T>>.

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]> {

}

Детская площадка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...