【发布时间】:2021-11-15 11:52:36
【问题描述】:
我正在尝试从futures-signals library 将某些程序状态建模为Mutables,我想从某个字符串键标识的serde_json Value 一般设置其值。
例如,假设我收到了一些负载,指示我用Value 更新"my_int",我希望能够设置Mutable 的值,即"my_int"。
我的想法是创建一个从 "my_int" 等标识符到可变设置器周围的 非模板化 包装器的映射。重要的是,所述包装器是非模板化的,否则我无法在一个地图中保存它们的集合:
let my_int = Mutable::new(123);
let my_str = Mutable::new("asdf");
// ...
let setters = HashMap::from([
("my_int", /* magic wrapper around setter here somehow */),
("my_str", /* magic wrapper around setter here somehow */),
// ...
]);
let property_name = "my_int"; // constant for demo purposes
let value = Value::from(234); // constant for demo purposes
let setter = setters.get(property_name).unwrap();
(setter.deser_and_set)(value);
现在说魔术包装看起来像这样:
struct SetterWrapper<'a> {
name: &'static str,
deser_and_set: &'a dyn Fn(Value) -> Result<(), Error>,
// + some other unrelated fields
}
我可以创建那些内联,而且它有效:
let my_int_setter = SetterWrapper {
name: "my_int",
deser_and_set: &(|v: Value| {
my_int.set(serde_json::from_value(v)?);
Ok(())
}),
// + some other unrelated fields
};
但是我有很多可变变量,不想为每个变量重复上面的代码,所以我尝试将它放入一个函数中:
fn wrap_setter<'a, T>(name: &'static str, mutable: &'a Mutable<T>) -> SetterWrapper<'a>
where T: for<'de> Deserialize<'de>
{
let deser_and_set = |v: Value| {
mutable.set(serde_json::from_value::<T>(v)?);
Ok(())
};
SetterWrapper {
name,
deser_and_set: &deser_and_set,
}
}
我打算像let my_int_setter = wrap_setter("my_int", &my_int);一样使用它,但是我遇到了以下错误:
error[E0515]: cannot return value referencing local variable `deser_and_set`
--> src\main.rs:66:5
|
66 | / SetterWrapper {
67 | | name,
68 | | deser_and_set: &deser_and_set,
| | -------------- `deser_and_set` is borrowed here
69 | | }
| |_____^ returns a value referencing data owned by the current function
错误本身对我来说很有意义:当然我不能返回对局部变量的引用,因为它们会悬空。但我相信从概念上讲,我可以通过以某种方式将函数中的闭包标记为与可变的生命周期相同,即'a,来解决这个问题,但你不能给变量生命周期注释。
我该如何解决这个问题?还是我的方法已经笨拙了?
【问题讨论】:
-
您可以在您的
SetterWrapper中添加Box<dyn Fn(Value) -> Result<(), Error>>,而不是引用。或者将wrap_setter定义为宏而不是函数。