gpt4 book ai didi

rust - 返回捕获引用的高级闭包

转载 作者:行者123 更新时间:2023-12-04 11:54:44 25 4
gpt4 key购买 nike

我正在尝试在返回闭包的结构上编写一个方法。这个关闭应该需要一个 &[u8]具有任意生命周期 'inner作为参数并返回相同的类型,&'inner [u8] .为了执行它的功能,闭包还需要一个(共享的)对结构体 &self 成员的引用。 .这是我的代码:

#![warn(clippy::pedantic)]

// placeholder for a large type that I can't afford to clone
struct Opaque(usize);

struct MyStruct<'a>(Vec<&'a Opaque>);

impl<'a> MyStruct<'a> {
pub fn get_func_for_index(
&'a self,
n: usize,
) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;

Some(move |i: &[u8]| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
})
}
}

fn main() {
let o1 = Opaque(1);
let o5 = Opaque(5);
let o7 = Opaque(7);

let x = MyStruct(vec![&o1, &o5, &o7]);

let drop_five = x.get_func_for_index(1 /*Opaque(5)*/).unwrap();

let data: Vec<u8> = Vec::from(&b"testing"[..]);

assert_eq!(drop_five(&data[..]), b"ng");
}
如果我尝试用 rustc 1.54.0 (a178d0322 2021-07-26) 编译它,我收到以下错误:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 14:14...
--> /tmp/lifetimes.rs:14:14
|
14 | Some(move |i: &[u8]| {
| ______________^
15 | | // placeholder: do something with the input using the &Opaque
16 | | &i[opaque.0..]
17 | | })
| |_________^
note: ...so that reference does not outlive borrowed content
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 6:6...
--> /tmp/lifetimes.rs:6:6
|
6 | impl<'a> MyStruct<'a> {
| ^^
note: ...so that return value is valid for the call
--> /tmp/lifetimes.rs:10:17
|
10 | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: higher-ranked subtype error
--> /tmp/lifetimes.rs:7:5
|
7 | / pub fn get_func_for_index(
8 | | &'a self,
9 | | n: usize,
10 | | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| |_______________________________________________________________________^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.
这是相当一口,我真的不明白它想告诉我什么。第一部分( first, the lifetime... )对我来说很有意义,返回的切片不能超过闭包参数。第二部分( but, the lifetime... )对我来说似乎很奇怪 - + 'a方法签名中的注解指的是闭包本身(因为它捕获了 &'a self.foo),而不是闭包返回的值。
是否可以更改代码以在 rust 中正确建模,或者目前不支持此构造?

最佳答案

问题在这里:

Some(move |i: &[u8]| {
&有生命周期,无论是否明确。 &[u8]的生命周期是多少? ?很明显,它应该是“闭包调用者选择的生命周期”(即更高等级的生命周期)。但是当编译器遇到一个带有空闲生命周期参数的引用类型时,即使在一个闭包的参数列表中,它也会 不是 假设生命周期排名更高。您收到的关于“匿名生命周期 #1”的错误消息是编译器困惑地试图使非排名更高的生命周期工作。
理论上,编译器可以从 impl Fn“向后”工作。在返回类型中,并认识到闭包的类型需要具有更高排名的生命周期。在这种情况下这样做还不够聪明,但有一种方法可以说服它:使用带有有界类型参数的局部函数将闭包的类型限制为您想要的范围。
pub fn get_func_for_index(
&self, // note 1
n: usize,
) -> Option<impl 'a + for<'inner> Fn(&'inner [u8]) -> &'inner [u8]> { // note 2
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;

// helper function to constrain the closure type
fn check<F: Fn(&[u8]) -> &[u8]>(f: F) -> F { // note 3
f
}

Some(check(move |i| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
}))
}
Playground
请注意以下事项:
  • &'a self这个函数太保守了,因为 'a是引用 self 的生命周期参数包含,而不是 self 的生命周期是借来的。一般来说,你几乎不应该写 &'a self&'a mut self哪里'a是来自外部作用域的命名生命周期。
  • 我找到了 + 'a很容易在 long trait 的末尾错过,尤其是 Fn具有返回类型的特征。我建议在这种情况下将生命周期放在首位(将其放在首位),以明确它与 impl 的关系更大。比到 &'inner [u8] .这是一种风格选择。
  • Fn(&[u8]) -> &[u8]实际上和for<'inner> Fn(&'inner [u8]) -> &'inner [u8]完全一样,因为 Fn 的省略规则特征与常规函数相同。无论哪种方式都很好;我发现较短的版本更容易阅读。

  • 类似问题
  • Expected bound lifetime parameter, found concrete lifetime [E0271]
  • How to declare a lifetime for a closure argument?
  • 关于rust - 返回捕获引用的高级闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69048869/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com