首页 > 解决方案 > 强类型枚举作为 rust 中的联合:如何确定值的类型并检索它;如何做“构造函数”

问题描述

类型化社区,来自 C++ 我正在寻找一种解决方案来将不同类型的值存储在 Rust 的结构中。总体思路是将优先级队列存储在 Hashmap 中并按队列名称索引,允许添加条目并按时间戳排序。这些条目应该能够保存先前定义类型的值字段。用例是能够对值进行版本控制,并在需要时通过附加字段注释值。

在 C++ 中,我将通过从定义的接口和存储指向该结构的指针的列表的继承,或通过 void 指针和指示枚举字段的类型来做到这一点。

到目前为止,我发现 Rust 使用了一个类型化的枚举。我的问题是“类型转换”是如何工作的(据我了解,在内存安全方面,Rust 中的范式可能与 C++ 中的不同,因为我在 C++ 中执行此操作的方式需要 RTTI 或类型转换)。在 Rust 中执行此操作的正确方法是什么?

例子:

enum Value {
    Int(i64),
    Float(f64),
    Str(String),
}

struct Entry {
    timestamp:i64,
    value: Value,
}

struct VersionList {
    name: String,
    entries: LinkedList<Entry>
}

现在的问题是,如果值的类型未知,Rust 中提取列表值的范式是什么。一种方法是为每个值类型创建一个方法并在其中有一个匹配表达式,如果匹配则返回具有正确类型的值,否则返回 None。但是,这意味着始终需要调用所有方法,直到其中一个确实返回实际值而不是 None,这会产生大量代码。

例子:

impl Entry {
pub fn get_i64(&self) -> Option<i64> {
    match &self.value {
        Value::Int(i) => Some(*i),
            _ => None
    }
}

另外,我意识到 Rust 没有构造函数的概念。因此,为了创建值,我创建了一个函数来写入正确的字段。在 Rust 中有不同的方法吗?

impl Entry {

    fn new_int(value: i64, timestamp: i64, user_id: String) -> Entry {
        //pub fn new(value: i64, timestamp: i64, user_id: String) -> Property {
        Entry {
            timestamp: timestamp,
            value: Value::Int(value),
        }
    }

    fn new_str(value: String, timestamp: i64, user_id: String) -> Entry {
        Entry {
            timestamp: timestamp,
            value: Value::Str(value),
        }
    }
...
}

谢谢您的帮助。

标签: typesenumsconstructorrust

解决方案


是的,就像@Jmb 的回答和我的评论一样,我不太确定你为什么需要进行类型转换。

但如果您需要对所有数据类型进行一些通用操作,我建议创建一个特征(这应该是 C++ 接口的替代方案)。

use std::collections::LinkedList;
use std::fmt::Display;

#[derive(Debug)]
struct Value<T> {
    timestamp:i64,
    value: T,
}

trait Entry {
    fn print_out(&self);
    fn get_timestamp(&self) -> i64;
}

impl<T: Display> Entry for Value<T> {
    fn print_out(&self) {
        println!("{}", self.value);
    }

    fn get_timestamp(&self) -> i64 {
        self.timestamp
    }
}

struct VersionList {
    name: String,
    entries: LinkedList<Box<dyn Entry>>
}

impl VersionList {
    pub fn new() -> Self {
        VersionList { name: "test".to_owned(), entries: LinkedList::<Box<dyn Entry>>::new() }
    }

    pub fn put<T: Display + 'static>(&mut self, value: Value<T>) {
        self.entries.push_back(Box::new(value));
    }
}

fn main() {
    let mut list = VersionList::new();
    list.put(Value {timestamp: 3, value: "abc".to_owned()});
    list.put(Value {timestamp: 1, value: 1});
    list.put(Value {timestamp: 2, value: 1.5});
    let iter = list.entries.iter();
    for ent in iter {
        ent.print_out();
    }

    println!("{}", "=".repeat(80));

    let mut vec = list.entries.iter().collect::<Vec<_>>();
    vec.sort_by(|a, b| a.get_timestamp().cmp(&b.get_timestamp()));
    for ent in vec.iter() {
        ent.print_out();
    }
}

推荐阅读