我发现让编译器指导我很有用:
fn to_words(text: &str) { // Note no return type
text.split(' ')
}
编译给出:
error[E0308]: mismatched types
--> src/lib.rs:5:5
|
5 | text.split(' ')
| ^^^^^^^^^^^^^^^ expected (), found struct `std::str::Split`
|
= note: expected type `()`
found type `std::str::Split<'_, char>`
help: try adding a semicolon
|
5 | text.split(' ');
| ^
help: try adding a return type
|
3 | fn to_words(text: &str) -> std::str::Split<'_, char> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
遵循编译器的建议并将其复制粘贴作为我的返回类型(进行一些清理):
use std::str;
fn to_words(text: &str) -> str::Split<'_, char> {
text.split(' ')
}
问题是您无法返回特征,Iterator
因为特征没有大小。这意味着Rust不知道要为该类型分配多少空间。您也不能返回对局部变量的引用,因此返回&dyn Iterator
不是启动器。
Impl性状
从Rust 1.26开始,您可以使用impl trait
:
fn to_words<'a>(text: &'a str) -> impl Iterator<Item = &'a str> {
text.split(' ')
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
有关如何使用它的限制。您只能返回一个类型(无条件!),并且必须在自由函数或固有实现上使用它。
盒装
如果您不介意降低效率,则可以返回Box<dyn Iterator>
:
fn to_words<'a>(text: &'a str) -> Box<dyn Iterator<Item = &'a str> + 'a> {
Box::new(text.split(' '))
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
这是允许动态调度的主要选项。也就是说,代码的确切实现是在运行时而不是编译时确定的。这意味着它适用于需要根据条件返回多个以上具体迭代器类型的情况。
新类型
use std::str;
struct Wrapper<'a>(str::Split<'a, char>);
impl<'a> Iterator for Wrapper<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
fn to_words(text: &str) -> Wrapper<'_> {
Wrapper(text.split(' '))
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
输入别名
如雷姆所指出
use std::str;
type MyIter<'a> = str::Split<'a, char>;
fn to_words(text: &str) -> MyIter<'_> {
text.split(' ')
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
处理关闭
当impl Trait
无法使用时,闭包会使事情变得更加复杂。闭包创建匿名类型,而这些不能在返回类型中命名:
fn odd_numbers() -> () {
(0..100).filter(|&v| v % 2 != 0)
}
found type `std::iter::Filter<std::ops::Range<{integer}>, [closure@src/lib.rs:4:21: 4:36]>`
在某些情况下,可以将这些闭包替换为可以命名为的函数:
fn odd_numbers() -> () {
fn f(&v: &i32) -> bool {
v % 2 != 0
}
(0..100).filter(f as fn(v: &i32) -> bool)
}
found type `std::iter::Filter<std::ops::Range<i32>, for<'r> fn(&'r i32) -> bool>`
并遵循以上建议:
use std::{iter::Filter, ops::Range};
type Odds = Filter<Range<i32>, fn(&i32) -> bool>;
fn odd_numbers() -> Odds {
fn f(&v: &i32) -> bool {
v % 2 != 0
}
(0..100).filter(f as fn(v: &i32) -> bool)
}
处理条件
如果需要有条件地选择一个迭代器,请参阅有条件地迭代多个可能的迭代器之一。