what is "required by this bound in `map`"? - rust

This code is from rustlings iterators2.rs
Why can't use capitalize_first as map's argument directly?
// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => format!("{}{}", first.to_ascii_uppercase(), &input[1..]),
}
}
// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
words.iter().map(capitalize_first).collect() // <-- Error
}
// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {
words.iter().map(|str| capitalize_first(str)).collect()
}
Errors:
error[E0631]: type mismatch in function arguments
--> exercises/standard_library_types/iterators2.rs:24:22
|
11 | pub fn capitalize_first(input: &str) -> String {
| ---------------------------------------------- found signature defined here
...
24 | words.iter().map(capitalize_first).collect()
| --- ^^^^^^^^^^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected function signature `fn(&&str) -> _`
found function signature `for<'r> fn(&'r str) -> _`
note: required by a bound in `map`
--> /Users/mattzhou/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:779:12
|
779 | F: FnMut(Self::Item) -> B,
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
```
I don't understand what does "required by this bound in map" mean. What's the different of calling a closure or a function?

Read the whole error message, not just the last line.
error[E0631]: type mismatch in function arguments
...
= note: expected function signature `fn(&&str) -> _`
found function signature `for<'r> fn(&'r str) -> _`
You are trying to use a function that accepts &str but due to the iterator type you have, the argument to the mapping function is &&str. Recall that .iter() usually borrows the value it's called on and doesn't consume it, so it iterates over &T where T is the type of item in the collection. Since T is &str, &T is &&str.
You would have to use a lambda to dereference the nested reference, e.g.:
words.iter().map(|&s| capitalize_first(s)).collect()
Alternatively, you can use the copied() iterator function, which unwraps one level of references by copying the referent (a &str in this case, so the string data itself is not copied):
words.iter().copied().map(capitalize_first).collect()

Related

Cannot set default function closure [duplicate]

This question already has answers here:
Dynamically select a function to call without intermediate variables
(2 answers)
Closed 10 months ago.
I am trying to create a method that takes an Option<impl Fn() -> ()> as a parameter, and, if this parameter is Some(func), stores func as a closure, but, if it is None, stores some default function as the closure. Specifically, my code is as follows:
fn foo()
{
println!("HI");
}
fn bar(baz: Option<impl Fn () -> ()>)
{
let func = match baz {
Some(func) => func,
//None => foo,
None => unimplemented!()
};
func();
}
pub fn main() {
bar(Some(foo));
}
As-is, the code compiles, which indicates to me that foo is indeed something that should work with impl Fn () -> (). However, if I swap out the None arm of my match with the commented out None arm to set foo as my "default implentation", I get the following error:
error[E0308]: `match` arms have incompatible types
--> <source>:10:17
|
6 | fn bar(baz: Option<impl Fn () -> ()>)
| ---------------- this type parameter
7 | {
8 | let func = match baz {
| ________________-
9 | | Some(func) => func,
| | ---- this is found to be of type `impl Fn() -> ()`
10 | | None => foo,
| | ^^^ expected type parameter `impl Fn() -> ()`, found fn item
11 | | //None => unimplemented!()
12 | | };
| |_____- `match` arms have incompatible types
|
= note: expected type `impl Fn() -> ()`
found fn item `fn() {foo}`
error: aborting due to previous error
As far as I can tell from the error, it is saying that foo does not qualify as impl Fn() -> () within the function (though it did when passed in as a parameter). What am I missing here that causes this, and is there a way to accomplish what I want here (take an optional closure as a parameter, and use a default function as a closure if none provided)?
All the arms of a match statement must resolve to the exact same type.
With that in mind, let's replace impl Fn() -> () (which is also the same as impl Fn() BTW) with the generics that it represents:
fn bar<T>(baz: Option<T>) where T: Fn() {
// ...
}
impl Trait (in a function parameter) is syntactic sugar for regular generics, so this is "what the compiler sees".
Then let's look at the match:
fn bar<T>(baz: Option<T>) where T: Fn() {
let f = match baz {
Some(f) => f,
None => foo,
};
}
This can't work, because the type of foo is a special thing called a "function item" (essentially a unique type), but the type of f is a generic parameter T: it could be any type imaginable (as long as it implements Fn()). Clearly, these might be different, so Rust rejects the match statement as "having incompatible types".
What you're looking for is a trait object (though this comes at the cost of a heap allocation and vtable dispatch):
fn bar(baz: Option<impl Fn()>) {
let f: Box<dyn Fn()> = match baz {
Some(f) => Box::new(f),
None => Box::new(foo),
};
f();
}
Or, you can call the function immediately without storing in a variable:
fn bar(baz: Option<impl Fn()>) {
match baz {
Some(f) => f(),
None => foo(),
};
}
This is likely to be faster than the dyn Fn() approach above, though of course, if you are later storing it in a struct, this will not work.

Can Rust cast between function types when I don't care about some of the arguments?

I have 3 function types:
type ThreadedFunction = fn(&mut Thread, Object) -> FunctionResult;
type UniversalFunction = fn(&mut Thread, Unused) -> FunctionResult;
type Function = fn(&mut Thread, &Method) -> FunctionResult;
static_assertions::assert_eq_size!(primitives::Unused, &Method);
static_assertions::assert_eq_size!(primitives::Unused, Object);
The universal functions ignore the second parameter, so I'd like to be able to use them in the two other contexts. The sizes of Object, Unused and &Method are the same.
I would like to be able to do something like:
pub fn unused(thread: &mut Thread, _: Unused) -> FunctionResult {
NormalReturn
}
pub fn somewhere() -> ThreadedFunction {
unused as ThreadedFunction
}
This is unsafe:
error[E0605]: non-primitive cast: `for<'r> fn(&'r mut interpreter::Thread, interpreter::primitives::Unused) -> interpreter::FunctionResult {unused}` as `for<'r> fn(&'r mut interpreter::Thread, object::Object) -> interpreter::FunctionResult`
--> src/interpreter.rs:25:13
|
25 | unused as ThreadedFunction
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
Wrapping the cast in unsafe {} doesn't help.
This could be impossible, but it would be very convenient to be able to do as it would save a bunch of code duplication.
No, you cannot perform this cast because the function references have different types. All of the parameter types and return types must be the same for two functions to have the same type.
Instead, you can return a closure that doesn't capture any environment. Because of that, it can be automatically converted into a function:
fn somewhere() -> ThreadedFunction {
|a, b| unused(a, Unused)
}
That is equivalent to this wrapper function:
fn unused_adapted(thread: &mut Thread, _: Object) -> FunctionResult {
unused(thread, Unused)
}
fn somewhere() -> ThreadedFunction {
unused_adapted
}
See also:
Why does passing a closure to function which accepts a function pointer not work?

Why the mutable reference parameter of a closure doesn't outlive the function call?

I'm using cssparser crate to parse some CSS code. I would like to create a closure that is able to parse a type function. As a first step, I create a very simple code that way:
use cssparser::{Parser, ParserInput};
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser| {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}
I got the following error:
error[E0282]: type annotations needed for the closure `fn(&mut Parser<'_, '_>) -> std::result::Result<&str, _>`
--> src/main.rs:9:43
|
9 | p.expect_function_matching("type")?;
| ^ cannot infer type of error for `?` operator
|
= note: `?` implicitly converts the error value into a type implementing `From<BasicParseError<'_>>`
As read in this answer, I added the return type of my closure:
let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
};
I still have an error I don't understand:
error: lifetime may not live long enough
--> src/main.rs:9:9
|
8 | let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
| - ---------------------------------------- return type of closure is std::result::Result<&str, BasicParseError<'2>>
| |
| has type `&mut Parser<'1, '_>`
9 | p.expect_function_matching("type")?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
Apparently '1 is release before '2. How can it be the case as the parameter of my closure is a reference? It should still be alive after the call to my closure, right?
I tried to explicitly annotate the lifetime of my objects but I wasn't able to find the correct way to do it; I always have an "undeclared lifetime" error. For instance:
let parse_type = |p: &mut Parser<'i, '_>| -> Result<&str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
Unfortunately, closures can't declare lifetime arguments, which will be required to communicate the proper lifetimes for this function. Moving it out to a function gives a better error:
use cssparser::{Parser, ParserInput};
fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
}
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let res = parse_type(&mut parser);
}
error[E0106]: missing lifetime specifier
--> src\main.rs:3:41
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&'a str, cssparser::BasicParseError> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^
error[E0106]: missing lifetime specifier
--> src\main.rs:3:58
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^^^^^^^^^^^^^^^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&str, cssparser::BasicParseError<'a>> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
The compiler will try to deduce lifetimes automatically as best it can, but p has three lifetimes &'1 Parser<'2, '3> involved, so it doesn't know what lifetime &'_ str or BasicParseError<'_> should be deduced to.
Looking at the signature for Parser::expect_function_matching, you probably want:
fn parse_type<'i>(p: &mut Parser<'i, '_>) -> Result<&'i str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
}
Of course, while everything #kmdreko has said is absolutely correct, replacing your closure with a function will only work if you're not capturing any environment—and if that's the case, you could simply declare that parse_type is a function pointer with the relevant type and Rust will coerce the closure accordingly:
let parse_type: for<'i> fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = |p| {
p.expect_function_matching("type")?;
Ok("OK")
};
If however your closure does capture environment, then I guess the extension of #kmdreko's approach would be to define a struct to hold that environment and then have some implementation on that struct that defines an appropriate method. But that's a lot of grunt. You could instead make parse_type a trait object for one of the Fn traits and use an analog of the above approach:
let parse_type: &dyn for<'i> Fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = &|p| {
p.expect_function_matching("type")?;
Ok("OK")
};
In theory this will add an additional layer of indirection when invoking the closure, but I think in practice the optimiser will remove it (unless you pass the closure between functions, at least). And it'd be a pretty irrelevant expense in most cases anyway.
Finally, if your input_string actually comes from a function argument, then you'll be able to name its lifetime in the function signature and use that directly in your closure definition:
fn example<'i>(input_string: &'i str) {
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser<'i, '_>| -> Result<_, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}

Issue with lifetime parameters and function pointers

Consider this code:
struct WithLifetime<'a> {
s: &'a str
}
impl WithLifetime<'_> {
fn in_impl(&self) -> bool {
self.s == "a"
}
}
fn out_of_impl(wl: &WithLifetime<'_>) -> bool {
wl.s == "a"
}
fn higher_order(f: fn(&WithLifetime<'_>) -> bool) -> bool {
let s = "a";
let wl = WithLifetime { s };
f(&wl)
}
fn main() {
higher_order(out_of_impl); // This line compiles
higher_order(WithLifetime::in_impl); // This line does not
}
The final line of main fails to compile with this error:
error[E0308]: mismatched types
--> src/main.rs:23:18
|
23 | higher_order(WithLifetime::in_impl); // This line does not
| ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r WithLifetime<'s>) -> _`
found fn pointer `for<'r> fn(&'r WithLifetime<'_>) -> _`
As far as I can figure out, in_impl and out_of_impl should be exactly the same function. They both take a reference to a WithLifetime, and don't care about the lifetime of that reference or the lifetime parameter of the WithLifetime instance. Both should be valid parameters to pass to higher_order. The compiler does not agree.
What is the problem with passing in_impl to higher_order, and why doesn't the compiler allow this? What can I do to pass struct methods on structs with lifetime parameters to higher-order functions?
First, let's find out the types for all the 3 functions:
fn main() {
let x: i32 = out_of_impl;
let x: i32 = WithLifetime::in_impl;
let x: i32 = higher_order;
}
Playground
Type of out_of_impl:
for<'r, 's> fn(&'r WithLifetime<'s>) -> bool {out_of_impl}
Type of WithLifetime::in_impl:
for<'r> fn(&'r WithLifetime<'_>) -> bool {WithLifetime::<'_>::in_impl}
Type of higher_order:
fn(for<'r, 's> fn(&'r WithLifetime<'s>) -> bool) -> bool {higher_order}
higher_order accepts a function in which both the lifetimes aren't named until the function is called.
So it basically accepts a function which works for any lifetimes 'r and 's. out_of_impl satisfies that criteria.
But in case of WithLifetime::in_impl, the inner lifetime needs to be known beforehand for<'r> fn(&'r WithLifetime<'_>).
To pass WithLifetime::in_impl, you would need to change it to:
fn in_impl<'b, 'c>(abc: &'b WithLifetime<'c>) -> bool {
abc.s == "a"
}
Playground
Now, this function works for any arbitrary lifetimes 'b and 'c.
To accept in_impl without changing it, as #Milan did,
fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool {
let s = "a";
let wl = WithLifetime { s };
f(&wl)
}
Playground
Now, higher_order has a type:
for<'b> fn(for<'r> fn(&'r WithLifetime<'b>) -> bool) -> bool {higher_order}
It accepts a function where lifetime 'r is defined only when the function is called and liftime 'b is known beforehand.
This works for out_of_impl because it accepts any arbitrary lifetimes. Also works for in_impl because now the signature matches higher_order.
How does for<> syntax differ from a regular lifetime bound? has a pretty nice explaination for HRTB.
In higher_order function, wl is dropped before it is borrowed, instead, change that function to this
fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool {
let s = "a";
let wl= WithLifetime { s };
f(&wl)
}
EDIT:
In simple words, fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool this 'b means that higher_order body lifetime will match fn lifetime.
Otherwise, if fn don't care what lifetime higher_order has, and this implicitly means wl value too since it is the body of high_order function, then compiler can drop wl at the same line it is declared since point is to save memory, right?

value "does not live long enough", but only when using a function pointer

I'm trying to get the following simplified code to compile:
type FunctionType<'input> = fn(input_string: &'input str) -> Result<(), &'input str>;
fn okay<'input>(_input_string: &'input str) -> Result<(), &'input str> {
Ok(())
}
fn do_stuff_with_function(function: FunctionType) {
let string = String::new();
match function(string.as_str()) {
Ok(_) => {},
Err(_) => {},
}
}
fn main() {
do_stuff_with_function(okay);
}
The playground complains:
error[E0597]: `string` does not live long enough
--> src/main.rs:13:20
|
13 | match function(string.as_str()) {
| ^^^^^^ does not live long enough
...
18 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 11:1...
--> src/main.rs:11:1
|
11 | / fn do_stuff_with_function(function: FunctionType) {
12 | | let string = String::new();
13 | | match function(string.as_str()) {
14 | | Ok(_) => {},
... |
17 | |
18 | | }
| |_^
I understand why the error would be firing under other circumstances: string only lives as long as the execution of do_stuff_with_function, but do_stuff_with_function returns the value of function's invocation which includes a same-lifetime reference to its input value, i.e., string.
However, I'm confused on three points:
I match the result of the function call, then return () for both branches. Why does the lifetime of value returned by function matter if it's unconditionally thrown out?
If I replace the call to the parameter function with a direct reference to okay (which has an identical signature), it compiles without complaint.
The error message suggests (though does not state outright?) that the necessary lifetime is already the same as the actual lifetime.
TL;DR: Use the for<'a> syntax to have a specific lifetime for the function, rather than take one from the context where it's used.
Lifetime elision on args of do_stuff_with_function hides what's going on here. Your actual lifetime is:
fn do_stuff_with_function<'a>(function: FunctionType<'a>) {
This lifetime declared in function argument doesn't mean "some random short lifetime I'll come up with later", but rather "a lifetime that already exists at the point of calling this function".
These lifetime annotations are not wildcards, but more like identifiers to track where values came from and where they are going to. They can be used, for example, to clarify a situation like this:
fn do_stuff_with_function<'a>(function: FunctionType<'a>, t: &'a str) {
match function(t) {
Ok(_) => {},
Err(_) => {},
}
}
fn main() {
let string = String::new();
do_stuff_with_function(okay, string.as_str());
}
However, the problem is solvable in Rust, but just needs a more advanced syntax. For the purpose of the explanation, first, let's change it to:
fn do_stuff_with_function<'a, F>(function: F) where F: Fn(&'a str) -> Result<(), &'a str> {
That means "make a copy of do_stuff_with_function for every unique F which can be anything that looks like a function taking &'a str (etc.).
This is essentially the same (+ allows closures) as your code. However, I still had to name the lifetime as tied to the call of do_stuff_with_function<'a>.
So here's a freaky type magic:
fn do_stuff_with_function<F>(function: F) where F: for<'a> Fn(&'a str) -> Result<(), &'a str> {
Which allows moving definition of the lifetime from do_stuff_with_function to definition of the Fn using for<'a> syntax. This way it's specific to the F, rather than do_stuff_with_function arguments.

Resources