[英]How to implement a global and mutable HashMap with str as key and Trait as values?
I am trying to implement value key pairs whose key would be a string and the value would be an object type that implements some predefined functions.我正在尝试实现值键对,其键是字符串,值是实现一些预定义函数的对象类型。 The problem I encounter is that a Trait (which I use in this case as a kind of inheritance) does not have a predefined size and is not threads safely.
我遇到的问题是 Trait(在这种情况下我将其用作一种继承)没有预定义的大小并且不是安全的线程。
/// _State line to define the basis of the 'State'
/// type with signatures of specific functions
pub trait _State {
fn as_string(&self, text: String) -> String;
fn print(&self);
}
/// Status type to add your custom colors
pub struct RGBState {
name: String,
color: (u8, u8, u8),
character: String,
}
/// Default state type using preconfigured ANSI colors
pub struct State {
name: String,
color: Color,
character: String,
}
lazy_static! {
static ref StateOK: Mutex<State> = {
let mut state = State{
name: String::from("OK"),
color: Color::Green,
character: "+".to_string()
};
Mutex::new(state)
};
static ref STATES: Mutex<HashMap<&'static str, &'static Lazy<Mutex<dyn _State + 'static>>>> = {
let mut _states = HashMap::from(
[
(
"OK",
Lazy::new(StateOK)
)
]
);
Mutex::new(_states)
};
}
All source code is available on github (not compilable yiet): https://github.com/mauricelambert/TerminalMessages所有源代码都在 github 上提供(不可编译 yet): https ://github.com/mauricelambert/TerminalMessages
I use the external library lazy_static .我使用外部库lazy_static 。
I guess I should use the Mutex, Lazy or other types that would allow me to make a mutable and global value.我想我应该使用 Mutex、Lazy 或其他允许我创建可变和全局值的类型。
I have no idea how I will define the size of the objects that I will define in values and that can be of different types whose common basis are function signatures.我不知道如何定义我将在值中定义的对象的大小,这些对象可以是不同类型,其共同基础是函数签名。
The overall purpose of my code is to implement a DLL in Rust with interfaces in other languages that would allow to display formatted and colored messages in the console.我的代码的总体目的是在 Rust 中实现一个 DLL,该 DLL 具有其他语言的接口,允许在控制台中显示格式化和彩色消息。 Each element of the message formatting must be "configurable" by the developer (the color, the character that represents the type of message, the progress bar ect...).
消息格式的每个元素都必须由开发人员“配置”(颜色、表示消息类型的字符、进度条等......)。 It must be able to use any of these message types by calling a function in which it will have to specify the message type and the content of the message.
它必须能够通过调用必须指定消息类型和消息内容的函数来使用这些消息类型中的任何一种。
I implemented similar code in Python whose source code is on github: https://github.com/mauricelambert/PythonToolsKit/blob/main/PythonToolsKit/PrintF.py .我在 Python 中实现了类似的代码,其源代码在 github 上: https ://github.com/mauricelambert/PythonToolsKit/blob/main/PythonToolsKit/PrintF.py。 Here is a screenshot that represents what I would like to implement in this DLL: !
这是一个屏幕截图,代表我想在这个 DLL 中实现的内容:! TerminalMessages demonstration
TerminalMessages 演示
I am interested in all the suggestions about Best Practices in Rust and Code Optimization.我对所有关于 Rust 和代码优化最佳实践的建议感兴趣。
I think there are a couple of misconceptions in your code, imo:我认为您的代码中存在一些误解,imo:
HashMap
, you need wrap them in a Box
, because, as you already realized, trait objects are not Sized
.HashMap
中,您需要将它们包装在Box
中,因为正如您已经意识到的那样,特征对象不是Sized
。Mutex
because the entire HashMap
is already in a Mutex
.Mutex
中,因为整个HashMap
已经在Mutex
中。 With that in mind, here is a working implementation :考虑到这一点,这是一个有效的实现:
use std::{collections::HashMap, sync::Mutex};
use lazy_static::lazy_static;
/// Preconfigured ANSI colors constants
#[derive(Clone)]
pub enum Color {
Black, // 0
Red, // 1
Green, // 2
Yellow, // 3
Blue, // 4
Purple, // 5
Cyan, // 6
White, // 7
}
impl Color {
fn value(&self) -> i32 {
match *self {
Color::Black => 0,
Color::Red => 1,
Color::Green => 2,
Color::Yellow => 3,
Color::Blue => 4,
Color::Purple => 5,
Color::Cyan => 6,
Color::White => 7,
}
}
}
/// _State line to define the basis of the 'State'
/// type with signatures of specific functions
pub trait _State {
fn as_string(&self, text: String) -> String;
fn print(&self);
}
/// Default state type using preconfigured ANSI colors
#[derive(Clone)]
pub struct State {
name: String,
color: Color,
character: String,
}
impl _State for State {
fn as_string(&self, text: String) -> String {
format!(
"\x1b[3{color}m[{character}] {text}\x1b[0m",
color = self.color.value(),
character = self.character,
text = text,
)
}
fn print(&self) {
println!("{}", self.as_string(self.name.clone()));
}
}
lazy_static! {
static ref STATE_OK: State = {
State {
name: String::from("OK"),
color: Color::Green,
character: "+".to_string(),
}
};
static ref STATES: Mutex<HashMap<&'static str, Box<dyn _State + Send>>> = {
let _states: HashMap<&'static str, Box<dyn _State + Send>> = HashMap::from([
("OK", Box::new(STATE_OK.clone()) as Box<dyn _State + Send>),
(
"NOK",
Box::new(State {
name: String::from("NOK"),
color: Color::Yellow,
character: "-".to_string(),
}) as Box<dyn _State + Send>,
),
]);
Mutex::new(_states)
};
}
fn main() {
println!("{}", STATES.lock().unwrap().len());
for (key, value) in &*STATES.lock().unwrap() {
println!("{}:", key);
value.print();
println!("");
}
}
Those are more my opinion, take them or leave them.这些更多是我的意见,要么接受,要么离开。
trait _State
depend on Send
, as they all have to be Send
to be storable in the HashMap
.trait _State
依赖于Send
,因为它们都必须是Send
才能存储在HashMap
中。 This makes the HashMap
definition a little cleanerHashMap
定义更清晰state_entry
helper function to simplify initializationstate_entry
辅助函数以简化初始化use std::{collections::HashMap, sync::Mutex};
use lazy_static::lazy_static;
/// Preconfigured ANSI colors constants
#[derive(Clone)]
pub enum Color {
Black, // 0
Red, // 1
Green, // 2
Yellow, // 3
Blue, // 4
Purple, // 5
Cyan, // 6
White, // 7
}
impl Color {
fn value(&self) -> i32 {
match *self {
Color::Black => 0,
Color::Red => 1,
Color::Green => 2,
Color::Yellow => 3,
Color::Blue => 4,
Color::Purple => 5,
Color::Cyan => 6,
Color::White => 7,
}
}
}
/// _State line to define the basis of the 'State'
/// type with signatures of specific functions
pub trait _State: Send {
fn as_string(&self, text: String) -> String;
fn print(&self);
}
/// Default state type using preconfigured ANSI colors
#[derive(Clone)]
pub struct State {
name: String,
color: Color,
character: String,
}
impl _State for State {
fn as_string(&self, text: String) -> String {
format!(
"\x1b[3{color}m[{character}] {text}\x1b[0m",
color = self.color.value(),
character = self.character,
text = text,
)
}
fn print(&self) {
println!("{}", self.as_string(self.name.clone()));
}
}
fn state_entry(
name: &'static str,
entry: impl _State + 'static,
) -> (&'static str, Box<dyn _State>) {
(name, Box::new(entry))
}
lazy_static! {
static ref STATE_OK: State = {
State {
name: String::from("OK"),
color: Color::Green,
character: "+".to_string(),
}
};
static ref STATES: Mutex<HashMap<&'static str, Box<dyn _State>>> = {
Mutex::new(HashMap::from([
state_entry("OK", STATE_OK.clone()),
state_entry(
"NOK",
State {
name: String::from("NOK"),
color: Color::Yellow,
character: "-".to_string(),
},
),
state_entry(
"ERROR",
State {
name: String::from("ERROR"),
color: Color::Red,
character: "!".to_string(),
},
),
]))
};
}
fn main() {
println!("{} entries\n", STATES.lock().unwrap().len());
for (key, value) in &*STATES.lock().unwrap() {
println!("{}:", key);
value.print();
println!("");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.