[英]Lifetime issues: return struct containing reference to local closure
I am attempting to model some program state as Mutables
from the futures-signals
library , whose value I want to set generically from a serde_json Value
identified by some string key.我正在尝试将一些程序状态
Mutables
为futures-signals
库中的Mutables
,我想从由某个字符串键标识的serde_json Value
一般设置其值。
For example, given I received some payload instructing me to update "my_int"
with a Value
, I want to be able to set the value of the Mutable
that is known as "my_int"
.例如,假设我收到了一些指示我用
Value
更新"my_int"
负载,我希望能够设置称为"my_int"
的Mutable
的值。
My idea was to have a map from identifiers like "my_int"
to a non-templated wrapper around a mutable's setter.我的想法是有一个从像
"my_int"
这样的标识符到可变的 setter 的非模板包装器的映射。 It is important that said wrapper is non-templated, because otherwise I couldn't hold a collection of them in one map:重要的是,所述包装器是非模板化的,否则我无法在一张地图中保存它们的集合:
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);
Right now said magic wrapper looks like this:现在说的魔法包装器看起来像这样:
struct SetterWrapper<'a> {
name: &'static str,
deser_and_set: &'a dyn Fn(Value) -> Result<(), Error>,
// + some other unrelated fields
}
And I can create those inline , and it works :我可以创建这些内联,它的工作原理:
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
};
But I have many mutables and don't want to repeat the above code for every one of them, so I attempted to put it into a function:但是我有很多可变的,不想为每一个都重复上面的代码,所以我试图把它放到一个函数中:
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,
}
}
which I intend to use like let my_int_setter = wrap_setter("my_int", &my_int);
我打算使用像
let my_int_setter = wrap_setter("my_int", &my_int);
, however I am encountering the following error: ,但是我遇到以下错误:
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
The error itself makes sense to me: of course I can't return references to local variables, as those would dangle.错误本身对我来说很有意义:当然,我不能返回对局部变量的引用,因为它们会悬垂。 But I believe conceptually I could solve the issue by somehow marking the closure in the function to have the same lifetime as the mutable, namely
'a
, but you cannot give variables lifetime annotations.但我相信从概念上讲,我可以通过某种方式将函数中的闭包标记为与可变的生命周期相同,即
'a
,但你不能给变量生命周期注释来解决这个问题。
How can I solve this issue?我该如何解决这个问题? Or is my approach already clumsy?
还是我的方法已经很笨拙了?
To work around the issue, one way I can think of is change the property deser_and_set
to a Box
from a reference.为了解决这个问题,我能想到的一种方法是将属性
deser_and_set
从引用更改为Box
。 With that, the ownership of the Box can be moved out of the function.这样,可以将 Box 的所有权移出函数。 Give it a try.
试一试。
struct SetterWrapper {
name: &'static str,
deser_and_set: Box<dyn Fn(Value) -> Result<(), Error>>,
// + some other unrelated fields
}
fn wrap_setter<T>(name: &'static str, mutable: &Mutable<T>) -> SetterWrapper
where T: for<'de> Deserialize<'de>
{
SetterWrapper {
name,
deser_and_set: Box::new(|v: Value| {
mutable.set(serde_json::from_value::<T>(v)?);
Ok(())
};),
}
}
Probably the answer from @Joe_Jingyu is cleaner but I want to point out a second way you could take:可能来自@Joe_Jingyu 的答案更清晰,但我想指出您可以采取的第二种方法:
make SetterWrapper
a trait and implement it for Mutable
:使
SetterWrapper
成为一个 trait 并为Mutable
实现它:
trait SetterWrapper {
fn deser_and_set(&self, v: Value) -> Result<(), Error>;
}
impl<T> SetterWrapper for Mutable<T>
where
T: for<'de> serde::de::Deserialize<'de>,
{
fn deser_and_set(&self, v: Value) -> Result<(), Error> {
self.set(serde_json::from_value::<T>(v)?);
Ok(())
}
}
Now you can create the HashMap with the trait objects and set the value:现在您可以使用 trait 对象创建 HashMap 并设置值:
let setters = HashMap::from([
("my_int", &my_int as &dyn SetterWrapper),
("my_str", &my_str),
]);
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();
// now the call can be direct
setter.deser_and_set(value).unwrap();
Playground link (Note: I have build a simple Mutable myself, just to make the example work) Playground 链接(注意:我自己构建了一个简单的 Mutable,只是为了让示例工作)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.