将Struct<'a> ::: method作为'for<'a>用于闭包的Fn(&Foo''a>)` [英] Pass a Struct<'a>::method as a `for<'a> Fn(&Foo<'a>)` for use in a closure

查看:52
本文介绍了将Struct<'a> ::: method作为'for<'a>用于闭包的Fn(&Foo''a>)`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在测试中,我有一个辅助函数,该函数可以在不同配置的对象上运行给定方法,其简化版本如下所示:

In my tests I had a helper function that runs a given method on differently configured objects, with a simplified version looking like this:

fn run_method<F>(f: F)
where
    F: Fn(&Foo),
{
    let to_test = vec![0i32];
    to_test
        .iter()
        .map(|param| {
            let foo = Foo(*param);
            f(&foo);
        })
        .for_each(drop);
}

// run_method(Foo::run);

这很好,直到我添加了对测试结构的引用,使其成为终身注释(对于缺少适当的用语,我的意思是 Foo <'a> )。

This worked fine until I added references to the tested struct, making it "lifetime-annotated" (for lack of a proper term, I mean Foo<'a>).

现在我得到一个错误,指出,我认为,Rust不想接受 Foo :: method 作为可以在任何给定生命周期内使用的函数(即 F: Fn(& Foo<'a>)),

Now I get an error indicating, I think, that Rust doesn't want to accept a Foo::method as a function that can be used with any given lifetime (i.e. F: for<'a> Fn(&Foo<'a>)), as required by the closure:

error[E0631]: type mismatch in function arguments
--> src/main.rs:54:5
   |
3  |     fn run(&self) {
   |     ------------- found signature of `for<'r> fn(&'r Foo<'_>) -> _`
...
54 |     run_method(Foo::run);
   |     ^^^^^^^^^^ expected signature of `for<'r, 's> fn(&'r Foo<'s>) -> _`
   |
note: required by `run_method`
--> src/main.rs:44:1
   |
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `for<'r, 's> <for<'t0> fn(&'t0 Foo<'_>) {Foo::<'_>::run} as std::ops::FnOnce<(&'r Foo<'s>,)>>::Output == ()`
--> src/main.rs:54:5
   |
54 |     run_method(Foo::run);
   |     ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `run_method`
--> src/main.rs:44:1
   |
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我可以通过避免闭包来解决该问题(尽管我不太了解'a 被限制为 run_method 的本地对象-生命周期参数不应该由调用者选择吗?):

I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?):

fn run_method<'a, F>(f: F)
where
    F: Fn(&Foo<'a>),
{
    let to_test = vec![&0i32];
    for param in to_test {
        let foo = Foo(param);
        f(&foo);
    }
}

我是否可以解决此问题而无需重写?如果不是-是否有理由不起作用?

Can I fix this without rewriting? If not - is there a reason why this shouldn't work?

完整代码:

struct Foo<'a>(&'a i32);
impl<'a> Foo<'a> {
    fn run(&self) {
        println!("Hello {}", self.0);
    }
}

fn run_method<F>(f: F)
where
    F: Fn(&Foo),
{
    //same as  F: for<'a> Fn(&Foo<'a>) {
    let to_test = vec![0i32];
    to_test
        .iter()
        .map(|param| {
            let foo = Foo(param);
            f(&foo);
        })
        .for_each(drop);
}

fn main() {
    run_method(Foo::run);
}

// This works:
// fn run_method<'a, F>(f: F)
// where
//     F: Fn(&Foo<'a>),
// {
//     let to_test = vec![&0i32];
//     for param in to_test {
//         let foo = Foo(param);
//         f(&foo);
//     }
// }

// The lifetime-less version:
// struct Foo(i32);
// impl Foo {
//     fn run(&self) {
//         println!("Hello {}", self.0);
//     }
// }
// 
// fn run_parser_method<F>(f: F)
// where
//     F: Fn(&Foo),
// {
//     let to_test = vec![0i32];
//     to_test
//         .iter()
//         .map(|param| {
//             let foo = Foo(*param);
//             f(&foo);
//         })
//         .for_each(drop);
// }
// 
// fn main() {
//     run_parser_method(Foo::run);
// }

游乐场

概述关于相同错误代码的其他问题:

An overview of other questions about the same error code:

  • Expected bound lifetime parameter, found concrete lifetime is about mismatch between trait definition and implementation (trait { fn handle<'a>(); } vs impl<'a> { fn handle() {} })
  • Function references: expected bound lifetime parameter , found concrete lifetime [E0271] as well as Expected bound lifetime parameter, found concrete lifetime [E0271] is about a closure |args| {...} without explicit type annotations (|args: &[&str]|) not being accepted as a Fn(&[&str]) -> (); the answers don't explain why (the latter hints that it was not implemented in 2015)
  • Type mismatch "bound lifetime parameter" vs "concrete lifetime" when filling a collection from a closure is again about a closure without explicit type annotations specifying that it accepts a reference (let mut insert = |k| seq.insert(k); (1..10).cycle().take_while(insert)), which masks a more useful "borrowed data cannot be stored outside of its closure" error.

推荐答案


我可以通过避免闭包来解决此问题(尽管我不太了解'a如何获取限制为run_method的本地对象-调用者不应该选择生命周期参数吗?)

I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?)

是。但是,当您在不使用闭包的情况下重写它时,您也将引用放入了 vec!调用中,因此不再在运行时构造该引用。相反,编译器可以推断 to_test 的类型为 Vec<&'static i32> ,并为'static 超过了所有呼叫者选择的生命周期,没有冲突。

It is. But when you rewrite it without closures, you have also put the reference inside the vec! invocation, so it is no longer constructed at runtime. Instead, the compiler can infer that to_test has type Vec<&'static i32>, and as 'static outlives any caller-chosen lifetime, there's no violation.

这无法按您期望的那样编译:

This fails to compile as you expect:

let to_test = vec![0i32];
for param in to_test.iter() {
    let foo = Foo(param);
    f(&foo);
}




有没有理由不这样做是

is there a reason why this shouldn't work?

是的,因为 run 的类型受该类型的限制 Foo 。更具体地说,您有一个由调用者决定的生存期(隐式地表示为 Foo 的类型),因此您必须构造一个 Foo 生存期的c $ c>对其调用给定的 run 引用。

Yes, because the type of run is constrained by the type of Foo. More specifically, you have a lifetime decided by the caller (implicitly, in the type for Foo), so you have to construct a Foo of that lifetime to invoke the given run reference on it.


是否可以解决此问题而无需重写?

Can I fix this without rewriting?

这取决于。

如果所有测试值都是文字,则表示可以进行'静态引用。

If all your test values are literals, you can make 'static references.

如果您能够并且愿意重写 run ,有可能不受 Foo

If you're able and willing to rewrite run, it's possible to make it unconstrained by the type of Foo

impl<'a> Foo<'a> {
    fn run<'s>(_self: &Foo<'s>) {
        println!("Hello {}", _self.0);
    }
}

但是然后不需要 impl 块。

我认为评论中提供的解决方案是您最好的选择,因为鉴于您不必关心您的具体 Foo<'a> 类型,无需提供该类型的方法引用。

I think the solution provided in the comments is your best bet, because given that you don't care about your concrete Foo<'a> type, there's no need to give the method reference for that type.

这篇关于将Struct&lt;'a&gt; ::: method作为'for&lt;'a&gt;用于闭包的Fn(&Foo''a>)`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆