-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Description
While working on a stackoverflow question I encountered the need for trait aliases. For example, this code (playground) uses a very long trait several times:
fn to_box_factory<F, RET>(f: F) -> impl Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>>
where
F: Fn(&'static str) -> RET,
RET: Iterator<Item = &'static str> + 'static,
{
move |s| Box::new(f(s))
}
fn main() {
let f1: &dyn Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>> = &to_box_factory(|s| s.split_whitespace());
let f2: &dyn Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>> = &to_box_factory(|s| s.split_ascii_whitespace());
let fs = vec![f1, f2];
fs[0]("rust 2020").for_each(|s| println!("{}", s));
fs[1]("rust 2020").for_each(|s| println!("{}", s));
}It would improve readability and reduce duplication to introduce a trait alias for Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>>. My attempt was to simply replace all uses of the trait with the alias, resulting in the following (playground):
#![feature(trait_alias)]
trait BoxFactory = Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>>;
fn to_box_factory<F, RET>(f: F) -> impl BoxFactory
where
F: Fn(&'static str) -> RET,
RET: Iterator<Item = &'static str> + 'static,
{
move |s| Box::new(f(s))
}
fn main() {
let f1: &dyn BoxFactory = &to_box_factory(|s| s.split_whitespace());
let f2: &dyn BoxFactory = &to_box_factory(|s| s.split_ascii_whitespace());
let fs = vec![f1, f2];
fs[0]("rust 2020").for_each(|s| println!("{}", s));
fs[1]("rust 2020").for_each(|s| println!("{}", s));
}However, that fails to compile with the following error:
error[E0271]: type mismatch resolving `<[closure@src/main.rs:9:5: 9:28 f:_] as std::ops::FnOnce<(&'static str,)>>::Output == std::boxed::Box<(dyn std::iter::Iterator<Item = &'static str> + 'static)>`
--> src/main.rs:4:36
|
4 | fn to_box_factory<F, RET>(f: F) -> impl BoxFactory
| --- ^^^^^^^^^^^^^^^ expected type parameter `RET`, found trait `std::iter::Iterator`
| |
| this type parameter
|
= note: expected struct `std::boxed::Box<RET>`
found struct `std::boxed::Box<(dyn std::iter::Iterator<Item = &'static str> + 'static)>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
= note: the return type of a function must have a statically known size
I'm not sure I understand that error, nor do I understand why the error doesn't appear in the first version.
Curiously, if I just replace -> impl BoxFactory with the full incantation of -> impl Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>> (playground), but leave the other two uses of the alias in main(), the code compiles and runs correctly. Is it a bug that returning impl Alias fails, while returning impl [original trait] works?
Note: I am aware that trait aliases are experimental. My motivation for reporting this issue is to ensure that problems with the feature (if any) are worked out before it is stabilized.