rust - 将内部引用传递给泛型闭包时的关联类型生存期
问题描述
这是一个编译良好的示例:
use std::cell::RefCell;
use std::rc::Rc;
struct Foo<'a> {
val: Rc<RefCell<i32>>,
dummy: Option<&'a i32>,
}
fn consume<T>(_: T) {}
impl<'a> Foo<'a> {
// Note that &i32 has no lifetime markers
fn subscribe<F>(self, func: F)
where
F: Fn(&i32) + 'a,
{
let val = self.val.clone();
consume(move |x: i32| {
*val.borrow_mut() = x;
func(&*val.borrow())
})
}
}
这是我想要实现但未编译的内容:
use std::cell::RefCell;
use std::rc::Rc;
trait Stream<'a> {
type Item: 'a;
fn subscribe<F>(self, func: F)
where
F: Fn(Self::Item) + 'a;
}
struct Bar<'a, S: Stream<'a>> {
stream: S,
val: Rc<RefCell<S::Item>>,
}
impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
type Item = &'a S::Item; // 'a doesn't seem right here...
fn subscribe<F>(self, func: F)
where
F: Fn(Self::Item) + 'a,
{
let val = self.val.clone();
self.stream.subscribe(move |x: S::Item| {
*val.borrow_mut() = x;
func(&*val.borrow());
})
}
}
这个例子几乎与第一个相同。唯一的区别是,因为它是一个特征,我们必须为关联类型分配一个显式的生命周期Item
,它是一个引用。将其设置为'a
会导致生命周期冲突(理所当然):
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:27:24
|
27 | func(&*val.borrow());
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 25:31...
--> src/lib.rs:25:31
|
25 | self.stream.subscribe(move |x: S::Item| {
| ^^^^^^^^^^^^^^^^^
note: ...so that closure can access `val`
--> src/lib.rs:27:20
|
27 | func(&*val.borrow());
| ^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 17:6...
--> src/lib.rs:17:6
|
17 | impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:27:18
|
27 | func(&*val.borrow());
| ^^^^^^^^^^^^^^
实际上,如果您要在函数签名中替换Fn(&i32)
为,则可以将第一个示例修改为失败并返回完全相同的错误。Fn(&'a i32)
是否可以编译第二个示例?可能通过使用一些黑客或不安全的块,我愿意接受任何真正的东西。如果需要,更改签名或重新调整逻辑。关联类型的生命周期应该Item
是多少?
解决方案
您可以通过指定F
必须能够处理更通用的生命周期来编译第一个示例:
impl<'a> Foo<'a> {
fn subscribe<F>(self, func: F)
where
for<'b> F: Fn(&'b i32) + 'a, // f can cope with any lifetime 'b
{
let val = self.val.clone();
consume(move |x| {
*val.borrow_mut() = x;
func(&*val.borrow())
})
}
}
据我所知,您的第二个示例至少存在另一个问题:您致电
self.stream.subscribe(move |x: S::Item| {
*val.borrow_mut() = x;
func(&*val.borrow());
})
但subscribe
接受一个接受借用的函数(即&S::Item
,不是S::Item
)。如果您传入参考,我不确定您是否/如何将其分配给val.borrow_mut
. 您可能必须将其转换为自有值。
正如您已经提到的,您也可以设置Item = S::Item
(不借用)。然而,这意味着您不能简单地传递val.borrow()
到func
闭包内,因为它会从借来的值中移动。同样,解决方案可能是以某种方式将其转换为拥有的价值。
推荐阅读
- android - 如何使用 Fabric crashlytics 中的本机 API?
- python - 如何替换txt文件中一列中的多列
- mysql - SQL 新手 - 使用索引加快速度
- reactjs - 我无法让我的 React UI 包在不构建的情况下自动编译 javascript
- kubernetes - 尝试在启用了 sidecar 的 pod 之间卷曲时从特使那里获得 403 Forbidden
- c# - 使用 C# 将制表符分隔的文本文件中的 HTML 读取为字符串
- javascript - 在 Angular 和 Ionic 应用程序中使用 async/await 的正确方法
- mysql - 仅当两列相同时才替换为
- css - CSS更改单选按钮标签
- node.js - 在 localhost 上运行两台服务器时收到 CORS 错误