es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Puedo especificar el tipo de iteradores basado en clausuras?

Escribí una función para iterar sobre los vecinos de las celdas en una cuadrícula 2D:

pub fn neighbours(
    (width, height): (usize, usize),
    (x, y): (usize, usize),
) -> impl Iterator<item =="" (usize,="" usize)=""> {
    [(-1, 0), (1, 0), (0, -1), (0, 1)]
        .iter()
        .map(move |(dx, dy)| (x as i64 + dx, y as i64 + dy))
        .filter(move |&(nx, ny)| 0 <= ny && ny < height as i64 && 0 <= nx && nx < width as i64)
        .map(|(nx, ny)| (nx as usize, ny as usize))
}

Ten en cuenta que devuelve una impl Iterator<item =="" (usize,="" usize)="">.

Si entiendo correctamente, devolver una impl resultaría en código más lento, llamando a punteros de función en lugar de compilar las cosas en bucles simples. ¿Verdad?

Por lo tanto, queriendo especificar un tipo más exacto, reemplacé el tipo con () para ver qué tipo infiere el compilador, y el resultado fue:

std::iter::Map<><><std::slice::iter<'l, (i64,="" i64)="">, _, _>, _>, _>

Donde los _ representan closures cuyos tipos no sé cómo especificar.

Intenté extraer los closures a structs con traits Fn pero no pude hacer que funcione y además, según entiendo, implementar traits Fn es una característica inestable y no debería usarla”.</std::slice::iter<‘l,>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, devolver una impl Iterator puede resultar en un código más lento y con cierta sobrecarga, ya que el compilador necesita generar un nuevo tipo para cada implementación del trait Iterator devuelto por la función. Sin embargo, en algunos casos también puede permitir un código más flexible y genérico.

    En tu caso, es correcto que al reemplazar el tipo de retorno por () le permite al compilador inferir un tipo más específico para el iterador, lo que potencialmente puede resultar en un código más rápido. Sin embargo, el tipo resultante puede ser bastante complejo y difícil de leer, como has señalado.

    Extraer los closures a structs con traits Fn es una posible solución, pero como también has mencionado, esta es una característica inestable de Rust y no se recomienda para uso general.

    Otro enfoque que podrías probar es usar la sintaxis impl Trait para especificar un tipo de retorno concreto, al tiempo que permite cierta flexibilidad en la implementación. Por ejemplo, podrías definir un alias de tipo para el tipo del iterador:

    type NeighboursIter = impl Iterator<item =="" (usize,="" usize)="">;
    

    Y luego usarlo como tipo de retorno de tu función neighbours:

    pub fn neighbours(
        (width, height): (usize, usize),
        (x, y): (usize, usize),
    ) -> NeighboursIter {
        // ...
    }
    

    Esto le dice al compilador que el tipo de retorno de la función neighbours debe ser un tipo que implemente el trait Iterator con un tipo Item de (usize, usize), pero permite que el tipo real sea determinado por la implementación de la función.

    Este enfoque puede proporcionar un buen equilibrio entre flexibilidad y rendimiento, y también debería hacer que el tipo resultante sea más fácil de leer y comprender.

Comments are closed.