我试图将结构存储在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();
}
Run Code Online (Sandbox Code Playgroud)
正如我所料,由于语法错误,这不起作用:
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();
}
Run Code Online (Sandbox Code Playgroud)
我的第二次尝试是存储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()();
}
Run Code Online (Sandbox Code Playgroud)
这失败了,因为这些fn项目具有不同的类型并且不能存储在相同的HashMap:
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
Run Code Online (Sandbox Code Playgroud)
由于我对 Rust 还很陌生,所以我没有想法。我怎么解决这个问题?
这最终从根本上是不可能的。在 Rust 中,局部变量存储在堆栈中,这意味着它们必须具有固定大小,在编译时已知。您的构造需要在运行时确定堆栈上值的大小。
最接近的选择是移动到trait objects,它引入了一个间接层:
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();
}
Run Code Online (Sandbox Code Playgroud)
你会在世界上发现这种模式,比如在 hyper 的NewService.
调用时[
&self方法的值new]是什么h["MyStruct"].new()
它是MyStructor的一个实例MyOtherStruct。同一个类型可以实现这两个特征的唯一原因是“工厂”和“实例”没有真正独特的状态。在更复杂的实现中,这将是两种不同的类型。
对于共享引用计数值等情况,使用相同类型是很常见的。
也可以看看:
| 归档时间: |
|
| 查看次数: |
1339 次 |
| 最近记录: |