I found myself writing different functions with an argument under the same bounds, like this:
pub fn foo<T>(mut self, path: T) -> Self where
T: IntoIterator,
T::Item: AsRef<str>,
{
// ...
}
pub fn bar<T>(mut self, path: T) -> Self where
T: IntoIterator,
T::Item: AsRef<str>,
{
// ...
}
Feeling this to be a bit of a chore, I tried to alias these bounds. But I didn’t find a way to. The closest I got, after checking a couple places[1],[2], is this:
trait Path {
type I: IntoIterator<Item = Self::S>;
type S: AsRef<str>;
}
impl<T, U> Path for T where
T: IntoIterator<Item = U>,
U: AsRef<str>,
{
type I = T;
type S = U;
}
Now, as an example, this compiles fine:
fn into_vec<T: Path>(it: T::I) -> Vec<String> {
it.into_iter()
.map::<String, _>(|x| x.as_ref().into())
.collect()
}
But when I try to use it:
fn consume<T: Path>() {
into_vec::<T>(&["one", "two"]);
}
I get the following error:
src/lib.rs:104:19: 104:34 error: mismatched types:
expected `<T as Path>::I`,
found `&[&str; 2]`
(expected associated type,
found &-ptr) [E0308]
src/lib.rs:104 into_vec::<T>(&["one", "two"]);
^~~~~~~~~~~~~~~
So, no luck. How can I go forward?
1 https://github.com/rust-lang/rust/issues/8634
2 https://stackoverflow.com/a/30424219/3957040
How can I go forward?
You can't directly. Let's look at your function:
fn consume<T: Path>() {
into_vec::<T>(&["one", "two"]);
}
This says "for any type that implements Path
, call into_vec
with a slice of strings". However, there's no way that you can guarantee that whatever the T
is, it will accept a slice of strings.
Looking in another direction, many types might accept a slice of strings, so it would make T
ambiguous.
Looking in a third direction, there's no way for type inference to decide what T
should be, as it's not used as an argument or return value.
You can get it to work by explicitly stating which T
you want:
fn consume() {
into_vec::<&[&'static str]>(&["one", "two"]);
}
To clarify, this has nothing to do with combining traits into another trait. This would be a problem with any trait.