Rust 在HashMap中存储类型以动态实例化它们
我试图将结构存储在按字符串设置键的Rust 在HashMap中存储类型以动态实例化它们,rust,Rust,我试图将结构存储在按字符串设置键的HashMap中,以便以后可以按字符串创建新对象。设想一个RESTAPI,客户机可以通过提供名称让服务器实例化特定对象 use std::collections::HashMap; struct MyStruct; impl MyStruct { pub fn new() -> Self { Self {} } } struct MyOtherStruct; impl MyOtherStruct { pub
HashMap
中,以便以后可以按字符串创建新对象。设想一个RESTAPI,客户机可以通过提供名称让服务器实例化特定对象
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", MyStruct);
h.insert("MyOtherStruct", MyOtherStruct);
// This is pseudo-code
let obj = h.get("MyStruct").unwrap()::new();
}
正如我所预料的,由于语法错误,这不起作用:
错误:应为`、`、`、`、`、`、`、`、`,或运算符,找到“::`
-->src/main.rs:25:41
|
25 |让obj=h.get(“MyStruct”).unwrap()::new();
|^^应为`.`、`、`?`、`、`、`、`、`、`、`、`、`、`、`、`,还是这里的接线员
我的第二次尝试是存储对每个结构的new
方法的引用,而不是类型本身
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", &MyStruct::new);
h.insert("MyOtherStruct", &MyOtherStruct::new);
let obj = h.get("MyStruct").unwrap()();
}
这会失败,因为fn
项具有不同的类型,并且不能存储在同一HashMap
中:
错误[E0308]:类型不匹配
-->src/main.rs:22:31
|
22 | h.插入(“MyOtherStruct”和MyOtherStruct::new);
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^预期的fn项
|
=注意:应为类型`&fn()->MyStruct{MyStruct::new}`
找到类型“%fn()->MyOtherStruct{MyOtherStruct::new}`
因为我对生锈还很陌生,所以我已经没有主意了。如何解决这个问题?这根本不可能。在Rust中,局部变量存储在堆栈上,这意味着它们必须具有在编译时已知的固定大小。构造需要在运行时确定堆栈上值的大小 最接近的替代方法是移动到trait对象,它引入了一层间接寻址:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {}
struct MyStruct;
impl NewThing for MyStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyStruct {}
struct MyOtherStruct;
impl NewThing for MyOtherStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyOtherStruct {}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStruct));
h.insert("MyOtherStruct", Box::new(MyOtherStruct));
let obj = h["MyStruct"].new();
}
使用std::collections::HashMap;
特征纽廷{
fn新建(和自)->框;
}
特质事物{}
结构MyStruct;
为MyStruct执行新任务{
fn新建(和自)->框{
框::新建(自{})
}
}
为MyStruct{}的impl Thing
结构MyOtherStruct;
MyOtherStruct的impl NewThing{
fn新建(和自)->框{
框::新建(自{})
}
}
MyOtherStruct{}的impl Thing
fn main(){
让mut h:HashMap=HashMap::new();
h、 插入(“MyStruct”,Box::new(MyStruct));
h、 插入(“MyOtherStruct”,框::新建(MyOtherStruct));
设obj=h[“MyStruct”].new();
}
你会在世界上找到这种模式,比如在hyper的
调用h[“MyStruct”]时,方法new
]的[code>&self
的值是多少。new()
它是MyStruct
或MyOtherStruct
的一个实例。同一类型可以实现这两个特性的唯一原因是“工厂”和“实例”没有真正的唯一状态。在更复杂的实现中,这将是两种不同的类型
在共享引用计数值等情况下,使用相同类型是常见的
另见:
- 这里是@Shepmaster解决方案的一个更复杂的例子,它为工厂和对象本身使用了不同的类型:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {
fn execute(&mut self);
}
// MyStruct
struct MyStructFactory;
impl NewThing for MyStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyStruct {test: 12, name: "Test".into()})
}
}
struct MyStruct {
test: i32,
name: String
}
impl Thing for MyStruct {
fn execute(&mut self) {
self.test+=1;
println!("MyStruct {} {}", self.test, self.name);
}
}
// MyOtherStruct
struct MyOtherStructFactory;
impl NewThing for MyOtherStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyOtherStruct {my_member: 1})
}
}
struct MyOtherStruct {
my_member: u32
}
impl Thing for MyOtherStruct {
fn execute(&mut self) { println!("MyOtherStruct.my_member: {}", self.my_member); }
}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStructFactory));
h.insert("MyOtherStruct", Box::new(MyOtherStructFactory));
h["MyStruct"].new().execute();
h["MyOtherStruct"].new().execute();
}
使用std::collections::HashMap;
特征纽廷{
fn新建(和自)->框;
}
特质事物{
fn执行(&mut self);
}
//我的结构
结构MyStructFactory;
为MyStructFactory实施新技术{
fn新建(和自)->框{
Box::new(MyStruct{test:12,名称:“test”.into()})
}
}
结构MyStruct{
测试:i32,
名称:String
}
为我的结构做些什么{
fn执行(&mut self){
自测试+=1;
println!(“MyStruct{}{}”,self.test,self.name);
}
}
//肌结构
结构工厂;
为Myotherstruct工厂实施新技术{
fn新建(和自)->框{
框::新建(MyOtherStruct{my_成员:1})
}
}
结构MyOtherStruct{
我的会员:u32
}
MyOtherStruct的impl Thing{
fn执行(&mutself){println!(&MyOtherStruct.my_成员:{},self.my_成员);}
}
fn main(){
让mut h:HashMap=HashMap::new();
h、 插入(“MyStruct”,Box::new(MyStructFactory));
h、 插入(“MyOtherStruct”,框::新建(MyOtherStructFactory));
h[“MyStruct”].new().execute();
h[“MyOtherStruct”].new().execute();
}
谢谢您的回答。在您提出的备选方案中,有一件事我不明白,那就是方法new
的参数&self
——调用h[“MyStruct”]。new()
?@Tyrant它是MyStruct
或mytherstruct
的一个实例。同一类型可以实现这两个特性的唯一原因是“工厂”和“实例”没有真正的唯一状态。在更复杂的实现中,这将是两种不同的类型。我将用一个更复杂的例子更新我的帖子,使用不同类型的“工厂”和“实例”。非常感谢你!