Consider this code:
fn f<T, F>(arg: T, check: F) -> bool
where
T: AsRef<str>,
F: Fn(T) -> bool,
{
let word = "bar";
check(word);
check(arg)
}
fn g() {
let _ = f("foo", |s| s.is_empty());
}
The line check(arg)
works: arg
is of T
, so fits the function signature of F
, which is simply Fn(T) -> bool
.
However, check(word)
does not compile:
error[E0308]: mismatched types
--> src/test.rs:7:11
|
1 | fn f<T, F>(arg: T, check: F) -> bool
| - this type parameter
...
7 | check(word);
| ----- ^^^^ expected type parameter `T`, found `&str`
| |
| arguments to this function are incorrect
|
= note: expected type parameter `T`
found reference `&str`
note: callable defined here
--> src/test.rs:4:8
|
4 | F: Fn(T) -> bool,
| ^^^^^^^^^^^^^
After some confusion, it dawned on me: while &str
implements AsRef<str>
(else, the call f("foo", ...)
inside of g
wouldn't be possible either), T
really is unknown and strictly treated as such; it could be anything, and in check(word)
I am trying to force T
to be &str
, which doesn't work.
Fine. Looking it the snippet, T
could be inferred as &str
in this instance but that of course doesn't work as f
could be called from more places, with types other than &str
but still implementing AsRef<str>
. Second, Rust treats its signatures strictly, so T
is T
, end of story.
Is there a workaround (needed) for this usage pattern? Any way I can come up with to use check
from within f
so far failed, as it inevitably ascribes a concrete type to T
.
Or am I trying to solve the wrong problem/using an antipattern? I want the user to supply an arg
, and also a check/callback to see whether a subpart (this is for working with substrings of arg
) is good to go to perform filtering.
(In the above case, word
being &str
is known statically: F: Fn(&str) -> bool
works fine actually, but is less flexible (and I'd love to understand why the above falls flat!).)