Hey all,
I currently have the following code (EDIT: Playground link):
use std::collections::BTreeMap;
use std::error::Error;
pub trait DeliveryConsumer: Send + Sync + Clone + Copy + 'static {
fn handle(self, consumer_tag: &str, envelope: &String, properties: &BTreeMap<String, String>, body: &[u8]) -> Result<(), Box<Error>>;
}
impl<F> DeliveryConsumer for F
where F: 'static + Send + Sync + Clone + Copy + FnOnce(&str, &String, &BTreeMap<String, String>, &[u8]) -> Result<(), Box<Error>>{
fn handle(self, consumer_tag: &str, envelope: &String, properties: &BTreeMap<String, String>, body: &[u8]) -> Result<(), Box<Error>> {
self(consumer_tag, envelope, properties, body)
}
}
fn test(a: impl DeliveryConsumer) {
let envelope = "foo".to_string();
let map = BTreeMap::new();
a.clone().handle("", &envelope, &map, &[0; 1]).unwrap();
}
fn test2() {
let argh = "";
test(move |consumer_tag/*: &str*/, envelope/*: &String*/, properties/*: &BTreeMap<String, String>*/, body/*: &[u8]*/| {
println!("{}", argh);
Ok(())
})
}
Which produces the following compilation error:
Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `for<'r, 's, 't0, 't1> <[closure@src/lib.rs:23:10: 26:6 argh:_] as std::ops::FnOnce<(&'r str, &'s std::string::String, &'t0 std::collections::BTreeMap<std::string::String, std::string::String>, &'t1 [u8])>>::Output == std::result::Result<(), std::boxed::Box<(dyn std::error::Error + 'static)>>`
--> src/lib.rs:23:5
|
23 | test(move |consumer_tag/*: &str*/, envelope/*: &String*/, properties/*: &BTreeMap<String, String>*/, body/*: &[u8]*/| {
| ^^^^ expected bound lifetime parameter, found concrete lifetime
|
= note: required because of the requirements on the impl of `DeliveryConsumer` for `[closure@src/lib.rs:23:10: 26:6 argh:_]`
note: required by `test`
--> src/lib.rs:15:1
|
15 | fn test(a: impl DeliveryConsumer) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0631]: type mismatch in closure arguments
--> src/lib.rs:23:5
|
23 | test(move |consumer_tag/*: &str*/, envelope/*: &String*/, properties/*: &BTreeMap<String, String>*/, body/*: &[u8]*/| {
| ^^^^ ---------------------------------------------------------------------------------------------------------------- found signature of `fn(_, _, _, _) -> _`
| |
| expected signature of `for<'r, 's, 't0, 't1> fn(&'r str, &'s std::string::String, &'t0 std::collections::BTreeMap<std::string::String, std::string::String>, &'t1 [u8]) -> _`
|
= note: required because of the requirements on the impl of `DeliveryConsumer` for `[closure@src/lib.rs:23:10: 26:6 argh:_]`
note: required by `test`
--> src/lib.rs:15:1
|
15 | fn test(a: impl DeliveryConsumer) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
However, if I change test2
to look like this:
fn test2() {
let argh = "";
test(move |consumer_tag: &str, envelope: &String, properties: &BTreeMap<String, String>, body: &[u8]| {
println!("{}", argh);
Ok(())
})
}
Then it all compiles correctly. I would have expected that the lifetime + closure argument types would be correctly implied here? It seems a bit strange to me that I need to explicitly specify the types in order for the lifetimes (which I haven't specified!) to be inferred correctly, but I might be missing what's actually happening here.
There might be some other issues here (e.g. do I really need to duplicate 'static + Send + ...
; do I even need all those traits?; is this even the right way to achieve my actual goal?) but I'd like to figure this particular quirk out first, then look at the other questions!