types - 强类型枚举作为 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),
}
}
...
}
谢谢您的帮助。
解决方案
是的,就像@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();
}
}
推荐阅读
- pandas - 如果条件发生在任何行/列中,则读取 Pandas 数据框
- web - 如何从网站列表中下载新文章?建议?
- c# - Windows 10 IoT Enterprise 2016 上的蓝牙 LE GATT 服务器
- flutter - 输入'列表
' 不是类型 'int' 的子类型 - firebase - Firebase:无法在 Firebase 中创建项目。" 创建项目时出现未知错误。请重试。"
- python - 使用 pytest 和假设进行异常处理和测试
- python - 如何通过将不同大小写的相同字母视为python中的相同字母来按字母顺序对列表进行排序
- c++ - 如何使用抽象类中不包含的方法
- apache - Solr '服务无法使用'
- office-js - 检测是否由加载项进行了更改