Derleyicinin bana rehberlik etmesine izin vermeyi yararlı buldum:
fn to_words(text: &str) { // Note no return type
text.split(' ')
}
Derleme şunları verir:
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> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Derleyicinin önerisini takiben ve bunu dönüş tipim olarak kopyalayıp yapıştırarak (biraz temizleme ile):
use std::str;
fn to_words(text: &str) -> str::Split<'_, char> {
text.split(' ')
}
Sorun şu ki, bir özelliğin Iterator
boyutu olmadığı için olduğu gibi bir özelliği geri dönemezsiniz . Bu, Rust'un tür için ne kadar alan ayıracağını bilmediği anlamına gelir. Sen , ya yerel bir değişkene gönderimi döndüremez böylece dönen, &dyn Iterator
olmayan bir marş olduğunu.
Impl özelliği
Rust 1.26'dan itibaren şunları kullanabilirsiniz 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());
}
Bunun nasıl kullanılacağına dair kısıtlamalar vardır. Yalnızca tek bir tür döndürebilirsiniz (koşulsuz!) Ve serbest bir işlevde veya doğal bir uygulamada kullanılmalıdır.
Kutulu
Biraz verimlilik kaybetmeyi düşünmüyorsanız, şunu döndürebilirsiniz 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());
}
Bu, dinamik gönderime izin veren birincil seçenektir . Yani, kodun tam olarak uygulanmasına derleme zamanında değil çalışma zamanında karar verilir. Bu, bir koşula bağlı olarak birden fazla somut yineleyici türü döndürmeniz gereken durumlar için uygun olduğu anlamına gelir.
Yeni tip
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());
}
Takma adı yazın
Reem tarafından işaret edildiği gibi
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());
}
Kapanışlarla başa çıkmak
Ne zaman impl Trait
kullanıma hazır değildir, kapanışları daha karmaşık şeyler yapmak. Kapanışlar anonim türler oluşturur ve bunlar dönüş türünde adlandırılamaz:
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]>`
Bazı durumlarda, bu kapamalar, adlandırılabilen işlevlerle değiştirilebilir:
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>`
Ve yukarıdaki tavsiyeye uyarak:
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)
}
Koşullarla başa çıkmak
Koşullu olarak bir yineleyici seçmeniz gerekiyorsa, olası birkaç yineleyiciden birinin Koşullu yineleme bölümüne bakın .