Saya merasa berguna untuk membiarkan kompiler memandu saya:
fn to_words(text: &str) { // Note no return type
text.split(' ')
}
Kompilasi memberi:
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> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Mengikuti saran kompiler dan copy-paste itu sebagai tipe kembalian saya (dengan sedikit pembersihan):
use std::str;
fn to_words(text: &str) -> str::Split<'_, char> {
text.split(' ')
}
Masalahnya adalah Anda tidak dapat mengembalikan sifat seperti Iterator
karena sifat tidak memiliki ukuran. Itu berarti Rust tidak tahu berapa banyak ruang yang dialokasikan untuk tipe tersebut. Anda juga tidak bisa mengembalikan referensi ke variabel lokal , jadi mengembalikan &dyn Iterator
adalah non-starter.
Menerapkan sifat
Mulai Rust 1.26, Anda dapat menggunakan 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());
}
Ada batasan tentang bagaimana ini bisa digunakan. Anda hanya dapat mengembalikan satu jenis (tanpa kondisional!) Dan itu harus digunakan pada fungsi bebas atau implementasi inheren.
Kemas
Jika Anda tidak keberatan kehilangan sedikit efisiensi, Anda dapat mengembalikan 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());
}
Ini adalah opsi utama yang memungkinkan pengiriman dinamis . Artinya, implementasi kode yang tepat diputuskan pada saat run-time, daripada waktu kompilasi. Artinya, ini cocok untuk kasus di mana Anda perlu mengembalikan lebih dari satu jenis iterator konkret berdasarkan suatu kondisi.
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());
}
Ketik alias
Seperti yang ditunjukkan oleh 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());
}
Berurusan dengan penutupan
Jika impl Trait
tidak tersedia untuk digunakan, penutupan membuat segalanya menjadi lebih rumit. Penutupan membuat tipe anonim dan ini tidak dapat dinamai dalam tipe kembalian:
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]>`
Dalam kasus tertentu, closure ini bisa diganti dengan fungsi, yang bisa dinamai:
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>`
Dan mengikuti saran di atas:
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)
}
Berurusan dengan persyaratan
Jika Anda perlu memilih iterator secara kondisional, lihat iterasi bersyarat pada salah satu dari beberapa kemungkinan iterator .