(See Bottom For Addendum)
Let's say I defined the following Struct:
struct Test<F>
where
F: Fn()
{
func: F
}
I then write a constructor:
impl<F> Test<F>
where
F: Fn()
{
pub fn new_1(func: F) -> Self {
Self {
func
}
}
}
I run main() with new_1():
fn main() {
Test::new_1(|| println!("oy"));
}
and the program compiles just fine.
So I decided to get risky.
I add this constructor:
impl<F> Test<F>
where
F: Fn()
{
pub fn new_2() -> Self {
Self {
func: || println!("oy")
}
}
}
and got the following error:
note: expected type parameter `F` found closure `[closure#src\mat_test.rs:23:22: 23:39]`
help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
I wasn't sure why Rust couldn't coerce this closure into F: Fn() this time as it could before, so I tried another constructor:
impl<F> Test<F>
where
F: Fn()
{
pub fn new_3() -> Self {
Self::new_1(|| println!("oy"))
}
}
which yielded the same error.
Why is it that I can initialize Test using a Closure only if the Closure is defined outside its impl block? What causes this behavior?
Addendum
This whole context, in reality, takes place inside of trait definition, but it seems that the impl trait return is not yet supported by traits. How could I go about implementing it in this case?
Related
I want to store a callback that can take different types of parameters (both owned values and references), and can also modify its environment (hence the FnMut). When invoking the callback with a reference, I'd like the compiler to enforce that the parameter is only valid in the closure body. I've tried to implement this using boxed closures.
A minimum example shown below:
fn main() {
let mut caller = Caller::new();
let callback = |x: &Foo| println!("{:?}", x);
caller.register(callback);
let foo = Foo{
bar: 1,
baz: 2,
};
//callback(&foo); // works
caller.invoke(&foo); // borrowed value does not live long enough
}
struct Caller<'a, T> {
callback: Box<dyn FnMut(T) + 'a>
}
impl<'a, T> Caller<'a, T> {
fn new() -> Self {
Caller {
callback: Box::new(|_| ()),
}
}
fn register(&mut self, cb: impl FnMut(T) + 'a) {
self.callback = Box::new(cb);
}
fn invoke(&mut self, x: T) {
(self.callback)(x);
}
}
#[derive(Debug, Clone)]
struct Foo {
bar: i32,
baz: i32,
}
I want to understand why this works if I directly call callback() but the compiler complains about lifetimes if I invoke it through a struct than owns the closure. Perhaps it has something to do with the Box? I can get this to work if I define foo before caller, but I'd like to avoid this.
This is yet another example of the compiler's type inference quirks when working with closures and bounds of a similar sort (issue #41078). Although this Caller<'a, T> may seem to be well capable of handling invoke calls for a given generic T, the given example passes a reference &'b Foo (where 'b would be some anonymous lifetime of that value). And due to this limitation, T was inferred to be a &Foo of one expected lifetime, which is different from a reference of any lifetime to a value of type Foo (for<'a> &'a Foo), and incompatible with the reference passed to the invoke call.
By not passing the closure to Caller, the compiler would be able to correctly infer the expected parameter type of the callback, including reference lifetime.
One way to overcome this is to redefine Caller to explicitly receive a reference value as the callback parameter. This changes the behavior of the inferred type &T into a higher-ranked lifetime bound, as hinted above.
Playground
fn main() {
let mut caller = Caller::new();
let callback = |x: &Foo| { println!("{:?}", x) };
caller.register(callback);
let foo = Foo { bar: 1, baz: 2 };
caller.invoke(&foo);
}
struct Caller<'a, T> {
callback: Box<dyn FnMut(&T) + 'a>,
}
impl<'a, T> Caller<'a, T> {
fn new() -> Self {
Caller {
callback: Box::new(|_| ()),
}
}
fn register(&mut self, cb: impl FnMut(&T) + 'a) {
self.callback = Box::new(cb);
}
fn invoke(&mut self, x: &T) {
(self.callback)(x);
}
}
One way to make this clearer would be to use the expanded definition of invoke:
fn register<F>(&mut self, cb: F)
where
F: for<'b> FnMut(&'b T) + 'a
{
self.callback = Box::new(cb);
}
See also:
Why is "one type is more general than the other" in an Option containing a closure?
Type mismatches resolving a closure that takes arguments by reference
How to declare a lifetime for a closure argument?
trait Responder{
}
struct App;
impl App {
fn new() -> Self {
Self {}
}
fn service<T, B>(&self, routes: T) -> Self where T: Fn()-> impl Responder {
Self {}
}
}
struct Routes {
data:String,
}
impl Responder for Routes{
}
fn routes() -> impl Responder {
Routes {
data: "Hello".to_string()
}
}
fn main() {
// let new_routes = routes;
App::new().service(routes);
}
How do I pass a function a parameter that return impl Trait or in my case impl Responder.
The error that it gives is: impl Trait not allowed outside of function and inherent method return types.
You can't - the docs (and the error) are explicit that the impl trait syntax can only be used when returning a value from a function to help the compiler deduce things (about a value). In your case you are trying to say something about a generic type, which is not the same and thus this syntax cannot be used.
Instead, you have to specify a type, in your case a generic one with a constraint:
fn service<T, B>(&self, routes: T) -> Self where T: Fn()->B, B: Responder
assuming you did not need B for something else. Note routes returns a value with a specific type, not an impl trait, and this type is what you are trying to write out.
While trying to implement a simple web server application using actix-web, I encountered apparently inconsistent behavior of Rust closures that do not know how to explain.
I had the following code:
use actix_web::{web, App, HttpServer};
#[derive(Clone)]
struct Config {
val1: String,
val2: String,
val3: String,
}
fn main() {
let conf = Config {
val1: "just".to_string(),
val2: "some".to_string(),
val3: "data".to_string(),
};
HttpServer::new(move ||
App::new().configure(create_config(&conf))
)
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
}
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
// Have to clone config because web::get().to by definition requires
// its argument to have static lifetime, which is longer than 'a
let my_own_conf_clone = conf.clone();
app.service(
web::scope("/user")
.route("", web::get().to(move || get_user(&my_own_conf_clone)))
);
}
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
This code works. Notice the closure I pass to web::get().to. I used it to pass the Config object down to get_user and still present web::get().to with a function that has no arguments, as it requires. At this point I decided to move the closure generation to a separate function:
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
app.service(
web::scope("/user")
.route("", web::get().to(gen_get_user(conf)))
);
}
}
fn gen_get_user(conf: &Config) -> impl Fn() -> String {
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
This code fails to compile with the following error:
error[E0277]: the trait bound `impl std::ops::Fn<()>: actix_web::handler::Factory<_, _>` is not satisfied
--> src/main.rs:30:39
|
30 | .route("", web::get().to(gen_get_user(conf)))
| ^^ the trait `actix_web::handler::Factory<_, _>` is not implemented for `impl std::ops::Fn<()>`
Why does it fail in the second case but not in first? Why was the trait Factory satisfied in the first case but isn't in the second? May be it's the factory's (its sources are here) fault? Is there a different way to return a closure, that would work in this situation? Any other approaches you could suggest? (Notice that Factory is not public so I cannot implement it directly myself)
If you wish to fool around with the code, I have it here: https://github.com/yanivmo/rust-closure-experiments
Notice that you can move between the commits to see the code in its working or failing states.
Then using impl Trait as return type all other type information other then that value implements Trait get erased.
In this particular case closure move || get_user(&my_own_conf_clone) implements Fn() -> String and Clone, but after returning Clone get erased.
But since Factory implemented for Fn() -> String + Clone, and not for Fn() -> String return value no longer implement factory.
This can be fixed by changing gen_get_user to
fn gen_get_user(conf: &Config) -> impl Fn() -> String + Clone{
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}
This question already has answers here:
"Expected type parameter" error in the constructor of a generic struct
(1 answer)
Returning a closure from a function
(4 answers)
Closed 4 years ago.
I almost have an intuitive sense of why this code should NOT work, but I can't quite put my finger on it. I think it has something to do with the fact that the new function would have a different return type every time.
Why is that a problem? Why does the direct creation work?
struct Struct<T>
where
T: Fn(&[u8]),
{
func: T,
}
impl<T> Struct<T>
where
T: Fn(&[u8]),
{
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
}
fn main() {
// this works
let s = Struct { func: |msg| {} };
}
The error is
error[E0308]: mismatched types
--> src/main.rs:14:24
|
14 | Struct { func: |msg| {} }
| ^^^^^^^^ expected type parameter, found closure
|
= note: expected type `T`
found type `[closure#src/main.rs:14:24: 14:32]`
tl;dr; You can do the following:
fn new() -> Struct<impl Fn(&[u8])> {
Struct { func: |msg| {} }
}
More detailed:
Let's dissect your impl block:
impl<T> Struct<T>
where
T: Fn(&[u8]),
{
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
}
We start with:
impl<T> Struct<T>
where
T: Fn(&[u8]),
This tells the compiler that the whole impl block is "valid" for any T satisfying Fn(&[u8]).
Now:
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
You say that new returns a Struct<T>, and we are within the block stating that everything inside it works for any T satisfying Fn(&[u8]). However, you return one particular instance of Struct, namely the one parametrized by |msg| {} - thus, the return value can not be a Struct<T> for any T satisfying Fn(&[u8]).
However, you can modify it to do the following:
fn new() -> Struct<impl Fn(&[u8])> {
Struct { func: |msg| {} }
}
This tells the compiler that new returns a Struct, whose parameter is known to satisfy Fn(&[u8]), so that the compiler should infer it. In particular it has no assumptions about T and returns one particular type.
In the direct initialization, however, we tell the compiler:
let s = Struct { func: |msg| {} };
The compiler sees that you want to create a Struct and knows that - in order to create it - it must infer the type for T res. func. It sees that you passed |msg| {} for func, infers the type for the closure and now knows a concrete type to put into the T.
I have two types: Lexer and SFunction.
SFunction stands for stateful function and is definined like so:
struct SFunction {
f: Option<Box<FnMut() -> SFunction>>,
}
The important part is that any SFunction references a closure that returns an SFunction.
Now I want to have these functions carry state by each affecting the same Lexer. This means that each of these SFunctions has to have a lifetime that depends on a specific Lexer.
Here's some more code if you want to get more of a sense of what I'm doing with this:
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lexNormal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(|| f(self)))
// SFunction { f: Some(Box::new(move ||f(self))) }
}
fn lexNormal(&mut self) -> SFunction {
return SFunction::empty()
}
}
(Here’s a full version of the code in the Rust playground.)
How do I specify this lifetime requirement in the code?
The compiler errors I'm getting say "cannot infer an appropriate lifetime for capture of self by closure due to conflicting requirements". I'm pretty sure the "conflicting requirements" here is that a Box type assumes the lifetime to be 'static. I could do something like Box<FnMut() -> SFunction + 'a> where 'a is a lifetime defined by the Lexer it depends upon, but I'm not sure how to define such an 'a.
Thanks for your help!
The problem is in this line:
SFunction::new(Box::new(|| f(self)))
Here, self is a reference to a Lexer, but there's no guarantee that the lexer will live long enough. In fact, it needs to live for the 'static lifetime! Without a lifetime specified, a boxed trait object will use the 'static lifetime. Said in code, these two declarations are equivalent:
<Box<FnMut() -> SFunction>>
<Box<FnMut() -> SFunction> + 'static>
And you can make your code compile (in an unsatisfactory way) by restricting it to accept only references that will live for the 'static lifetime:
fn lex(&'static mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&'static mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
Of course, it's very doubtful that you will have a Lexer with the static lifetime, as that would mean that it's lexing static data, which wouldn't be very useful. That means we need to include lifetimes in your trait object... as you suggested.
Ultimately what helped to see the problem was to restructure your closure a bit:
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || {
// f(self)
let s2 = self;
let f2 = f;
f2(s2)
}))
}
Compiling this produces an error that points to what seems to be the real problem:
<anon>:31:22: 31:26 error: cannot move out of captured outer variable in an `FnMut` closure [E0507]
<anon>:31 let s2 = self;
^~~~
<anon>:31:17: 31:19 note: attempting to move value to here
<anon>:31 let s2 = self;
^~
<anon>:31:17: 31:19 help: to prevent the move, use `ref s2` or `ref mut s2` to capture value by reference
I believe this is because a FnMut closure may be called multiple times, which would mean that the reference enclosed in the closure would need to be copied around, which would be bad news as &mut references should be unique.
All together, this code works:
struct SFunction<'a> {
f: Option<Box<FnOnce() -> SFunction<'a> + 'a>>,
}
impl<'a> SFunction<'a> {
fn new(f: Box<FnOnce() -> SFunction<'a> + 'a>) -> SFunction<'a> {
SFunction {
f: Some(f),
}
}
fn empty() -> SFunction<'a> {
SFunction {
f: None,
}
}
fn call(self) { }
}
struct Lexer;
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
fn lex_normal<'z>(&'z mut self) -> SFunction<'z> {
SFunction::empty()
}
}
fn main() {
let mut l = Lexer;
l.lex()
}
I hope my explanation is right and that the changed code still suits your use case!