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
      的一个实例。同一类型可以实现这两个特性的唯一原因是“工厂”和“实例”没有真正的唯一状态。在更复杂的实现中,这将是两种不同的类型。我将用一个更复杂的例子更新我的帖子,使用不同类型的“工厂”和“实例”。非常感谢你!