gpt4 book ai didi

rust - 在 HashMap 中存储类型以动态实例化它们

转载 作者:行者123 更新时间:2023-11-29 08:15:58 40 4
gpt4 key购买 nike

我正在尝试将结构存储在以字符串为键的 HashMap 中,以便以后可以通过字符串创建新对象。想一想 REST API,客户端可以在其中通过提供名称让服务器实例化特定对象。

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();
}

如我所料,由于语法错误,这不起作用:

error: expected one of `.`, `;`, `?`, or an operator, found `::`
--> src/main.rs:25:41
|
25 | let obj = h.get("MyStruct").unwrap()::new();
| ^^ expected one of `.`, `;`, `?`, or an operator here

我的第二次尝试是存储对每个结构的 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 中:

error[E0308]: mismatched types
--> src/main.rs:22:31
|
22 | h.insert("MyOtherStruct", &MyOtherStruct::new);
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected type `&fn() -> MyStruct {MyStruct::new}`
found type `&fn() -> MyOtherStruct {MyOtherStruct::new}`

由于我是 Rust 的新手,所以我没有想法。我该如何解决这个问题?

最佳答案

这根本上是不可能的。在 Rust 中,局部变量存储在堆栈中,这意味着它们必须具有固定大小,在编译时已知。您的构造需要在运行时确定堆栈上值的大小。

最接近的替代方法是转移到特征对象,它引入了一个间接层:

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();
}

您会在世界上找到这种模式,例如在 hyper 的 NewService 中.

what is [the value of &self of method new] when calling h["MyStruct"].new()

它是 MyStructMyOtherStruct 的实例。同一类型可以实现这两个特征的唯一原因是“工厂”和“实例”没有真正独特的状态。在更复杂的实现中,它们将是两种不同的类型。

在共享引用计数值等情况下,使用相同的类型很常见。

另见:

关于rust - 在 HashMap 中存储类型以动态实例化它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49587949/

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com