什么是正确的方式来返回一个迭代器(或任何其他性状)?
下面的Rust代码编译和运行没有任何问题。
fn main() { let text = "abc"; println!("{}", text.split(' ').take(2).count()); }
之后,我尝试了这样的东西….但它没有编译
fn main() { let text = "word1 word2 word3"; println!("{}", to_words(text).take(2).count()); } fn to_words(text: &str) -> &Iterator<Item = &str> { &(text.split(' ')) }
主要的问题是,我不确定什么返回types的函数to_words()
应该有。 编译器说:
error[E0599]: no method named `count` found for type `std::iter::Take<std::iter::Iterator<Item=&str>>` in the current scope --> src/main.rs:3:43 | 3 | println!("{}", to_words(text).take(2).count()); | ^^^^^ | = note: the method `count` exists but the following trait bounds were not satisfied: `std::iter::Iterator<Item=&str> : std::marker::Sized` `std::iter::Take<std::iter::Iterator<Item=&str>> : std::iter::Iterator`
什么是正确的代码,使其运行? ….我的知识差距在哪里?
我发现让编译器引导我很有用:
fn to_words(text: &str) { // Note no return type text.split(' ') }
编译提供:
error[E0308]: mismatched types --> src/main.rs:7:9 | 7 | text.split(' ') | ^^^^^^^^^^^^^^^ expected (), found struct `std::str::Split` | = note: expected type `()` found type `std::str::Split<'_, char>`
复制并粘贴,作为我的返回types(有一点清理):
use std::str; fn to_words(text: &str) -> str::Split<char> { text.split(' ') }
问题是你不能像Iterator
那样返回一个特征,因为特征没有大小。 这意味着Rust不知道为这个types分配多less空间。 你也不能返回一个局部variables的引用 ,所以返回&Iterator
是一个非启动器。
RFC 1522在那里承诺使这种方式更符合人体工程学,一旦实施。
在此期间,你有几个select..
盒装
如果你不介意失去一点效率,你可以返回一个Box<Iterator>
:
fn to_words<'a>(text: &'a str) -> Box<Iterator<Item = &'a str> + 'a> { Box::new(text.split(' ')) } fn main() { let text = "word1 word2 word3"; println!("{}", to_words(text).take(2).count()); }
这是允许dynamic调度的唯一选项。 也就是说,代码的确切实现是在运行时而不是编译时决定的。 这意味着这适用于需要返回多个具体types的迭代器的情况。
NEWTYPE
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()); }
input别名
正如reem所指出的那样
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特质
至于PR#35091 (现在只能在夜间使用Rust),您可以使用impl trait
:
#![feature(conservative_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()); }