我想使用返回类型为Fn
的{{1}}特征。
例如:
impl Trait
但是,此代码无法使用以下错误消息进行编译:
let funcs: [&Fn(&str) -> impl Iterator<Item = &str>] =
[&str::split_whitespace, &str::split_ascii_whitespace];
我应该怎么办?
答案 0 :(得分:0)
除了impl Trait
现在只能在有限的语法上使用的事实外,从语义上说,这仅意味着该位置将存在一种具体类型。它不是异构类型或动态调度的许可证。
这可以完成,但是很快变得笨拙:
type StrFn<'a> = &'a dyn Fn(&'static str) -> Box<dyn Iterator<Item = &'static str>>;
fn main() {
let f1: StrFn = &|s: &'static str| Box::new(s.split_whitespace());
let f2: StrFn = &|s: &'static str| Box::new(s.split_ascii_whitespace());
let fs = vec![f1, f2];
fs[0]("rust 2020").for_each(|s| println!("{}", s));
}
也许有更好的方法。
答案 1 :(得分:0)
str::split_whitespace
和str::split_ascii_whitespace
具有不同的返回类型。您不能构造各种类型的数组。相反,您可以创建boxed trait objects的数组。这将在运行时确定要调用的特定方法的地方执行动态调度(而不是在编译时知道特定方法版本的静态调度)
本质上,目标是使所有功能的签名为:
for<'a> fn(&'a str) -> Box<dyn Iterator<Item=&'a str> + 'a>
该函数需要一个&str
并在运行时确定的&str
上返回一些迭代器。
现在,这开始变得混乱起来,我希望有人可以提出一种更好的方法来实现这一目标。
一种可行的方法是在str::split_whitespace
和str::split_ascii_whitespace
周围创建包装函数,以返回盒装特征而不是它们各自的SplitWhitespace
和SplitAsciiWhitespace
结构。我已经使用了一个辅助宏来将来自函数调用的返回值包装在Box中
macro_rules! boxed_return {
($fn_new:ident, $fn:path) => {
fn $fn_new<'a>(s: &'a str) -> Box<dyn Iterator<Item=&'a str> + 'a> {
Box::new($fn(s))
}
}
}
boxed_return!(split_whitespace_wrapper, str::split_whitespace);
boxed_return!(split_ascii_whitespace_wrapper, str::split_ascii_whitespace);
然后我们可以简单地如下创建分离器函数数组
let funcs = [split_whitespace_wrapper, split_ascii_whitespace_wrapper];