Description
Description
This is a followup of forum post [Solved] Need help understanding compilation error with str.contains / String / Pattern.
Here's a function that compiles:
fn compiles() -> bool {
let word = String::from("hello");
"hello world".contains(&word)
}
But if I omit passing a reference to contains
and pass the actual String
:
fn wont_compile() -> bool {
let word = String::from("hello");
"hello world".contains(word) // <- missing "&" here before "word"
}
, then compilation fails with error
error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String`
--> src/lib.rs:96:19
|
96 | "hello world".contains(word)
| ^^^^^^^^ expected an `FnMut<(char,)>` closure, found `std::string::String`
|
= help: the trait `std::ops::FnMut<(char,)>` is not implemented for `std::string::String`
= note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String`
In this context, as a babbling Rustacean, I had zarroo idea of what rustc was trying to tell me and, assuming the solution (which I found by looking up a .contains()
example in the Rust book, where a &
reference was used), my incorrect concluding puzzlement was:
- How a
String
isn't astd::ops::FnMut<(char,)>
, but a reference to aString
is? - And what is a closure even doing here, where we're all talking
String
s?
As pointed by forum user krdln
, what's happening is that, as documented by str.contains, I should have passed a Pattern, whose 6 implementors are:
impl<'a> Pattern<'a> for char
impl<'a, 'b> Pattern<'a> for &'b str
impl<'a, 'b> Pattern<'a> for &'b String
impl<'a, 'b> Pattern<'a> for &'b [char]
impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool
, so rustc's logic behind the error message was:
"You’ve passed me something that is not a
char
,&str
,&String
,&[char]
nor&&str
, so it must be some other typeF
! If you want anF
to be a pattern, it must implementFnMut
!"
Proposal
When rustc fails to compile using the last (fallback? generic?) implementor for a trait,
- Warn that it reached the last implementor.
- List the missed implementors (always? If short enough? Abbreviated if too long? Only the count if too long? I don't know).
The updated, friendlier error message could look something like that:
error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String`
--> src/lib.rs:96:19
|
96 | "hello world".contains(word)
| ^^^^^^^^ expected an `FnMut<(char,)>` closure, found `std::string::String`
|
= help: the trait `std::ops::FnMut<(char,)>` is not implemented for `std::string::String`
// START ADDITION PROPOSAL =========================================
= help: reached last generic implementor for `std::str::pattern::Pattern<'_>`, maybe you meant to use one of the 5 other implementors:
char, &'b str, &'b String, &'b [char], &'c &'b str
// END ADDITION PROPOSAL =========================================
= note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String`
Note: hope the proposal makes sense, or at least you get the intention! I have no idea what I'm doing! This is my first Rust bug! I haven't even finished the Rust book! One last exclamation mark for the road!