recorrer que linkedlist iteradores for español rust

rust - que - ¿Cuál es la forma correcta de devolver un iterador(o cualquier otro rasgo)?



recorrer arraylist java foreach (1)

Me ha resultado útil dejar que el compilador me guíe:

fn to_words(text: &str) { // Note no return type text.split('' '') }

Compilar da:

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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Siguiendo la sugerencia del compilador y pegando copias como mi tipo de retorno (con un poco de limpieza):

use std::str; fn to_words(text: &str) -> str::Split<''_, char> { text.split('' '') }

El problema es que no puede devolver un rasgo como Iterator porque un rasgo no tiene un tamaño. Eso significa que Rust no sabe cuánto espacio asignar para el tipo. Tampoco puede devolver una referencia a una variable local, por lo que devolver &dyn Iterator no se inicia.

Rasgo implícito

A partir de Rust 1.26, puede usar el 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()); }

Existen restricciones sobre cómo se puede usar esto. Solo puede devolver un solo tipo (¡sin condicionales!) Y debe usarse en una función libre o una implementación inherente.

En caja

Si no le importa perder un poco de eficiencia, puede devolver un 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()); }

Esta es la opción principal que permite el despacho dinámico . Es decir, la implementación exacta del código se decide en tiempo de ejecución, en lugar de en tiempo de compilación. Eso significa que esto es adecuado para casos en los que necesita devolver más de un tipo concreto de iterador en función de una condición.

Nuevo tipo

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()); }

Escriba alias

Como lo señaló 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()); }

Tratar con cierres

Cuando el impl Trait no está disponible para su uso, los cierres complican las cosas. Los cierres crean tipos anónimos y no se pueden nombrar en el tipo de retorno:

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]>`

En ciertos casos, estos cierres se pueden reemplazar con funciones, que se pueden nombrar:

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>`

Y siguiendo los consejos anteriores:

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) }

Manejo de condicionales

Si necesita elegir condicionalmente un iterador, consulte Condicionalmente iterar sobre uno de varios iteradores posibles .

El siguiente código de Rust se compila y se ejecuta sin problemas.

fn main() { let text = "abc"; println!("{}", text.split('' '').take(2).count()); }

Después de eso, intenté algo como esto ... pero no se compiló

fn main() { let text = "word1 word2 word3"; println!("{}", to_words(text).take(2).count()); } fn to_words(text: &str) -> &Iterator<Item = &str> { &(text.split('' '')) }

El principal problema es que no estoy seguro de qué tipo de retorno debería tener la función to_words() . El compilador dice:

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`

¿Cuál sería el código correcto para hacer que esto se ejecute? .... y dónde está mi brecha de conocimiento?