我正在尝试在Rust中编写一个请求“路由器”:与匹配发生时要调用的函数关联的表达式列表。函数可能是来自各种对象的方法,这当然会使借阅检查器抱怨。这是我想要的示例:
use std::collections::HashMap;
struct Foo(bool);
impl Foo {
fn say(&self) {
println!("I'm {}", self.0);
}
fn morph(&mut self) {
self.0 = !self.0;
}
}
fn main() {
let mut foo = Foo(true);
let mut routes: HashMap<String, Box<FnMut()>> = HashMap::new();
routes.insert("foo/say".to_string(), Box::new(|| foo.say())); //< First (immutable) borrow of foo
routes.insert("foo/morph".to_string(), Box::new(|| foo.morph())); //< Second (mutable) borrow of foo
routes.insert("bar".to_string(), Box::new(|| println!("hello"))); //< Compiler also says immutable foo is used here
}
我理解为什么借用检查器对此不满意,但是我想知道在Rust中实现该功能的惯用方式是什么。
旁注:对获取异构函数列表/数组/哈希图的最佳方法的任何一般性评论,将不胜感激。
解决方案非常简单,真的。因为您将需要一个允许您按需获得可变借入的结构,所以需要RwLock
。而且因为我猜您正在构建的是HTTP路由器,所以要绕过Foo
上的生存期要求,您将需要将RwLock
包装在Arc
中,如下所示:
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
struct Foo(bool);
impl Foo {
fn say(&self) {
println!("I'm {}", self.0);
}
fn morph(&mut self) {
self.0 = !self.0;
}
}
fn main() {
let mut foo = Arc::new(RwLock::new(Foo(true)));
let mut routes: HashMap<String, Box<FnMut()>> = HashMap::new();
routes.insert("foo/say".to_string(), Box::new(|| foo.read().unwrap().say())); //< First (immutable) borrow of foo
routes.insert("foo/morph".to_string(), Box::new(|| foo.write().unwrap().morph())); //< Second (mutable) borrow of foo
routes.insert("bar".to_string(), Box::new(|| println!("hello"))); //< Compiler also says immutable foo is used here
}
请注意,我滥用了这样一个事实,即所有内容都只能为此借用foo
只读。如果您需要在闭包中添加move
内容,则Arc
实现Clone
,因此您绝对应该利用此优势。
其余的很好-只要您所有的闭包都具有相同的签名,将它们装箱并将它们存储在任何集合中都是习惯性的。