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.

Los genéricos con aritmética de enteros muestran “se esperaba el parámetro de tipo T, se encontró integer”.

Intento escribir una función genérica en Rust donde realice un cálculo aritmético. Desafortunadamente, el compilador no permite mezclar T con un entero. La primera función evens no genérica funciona, mientras que la segunda no se compila.

use itertools::Itertools;
use num::Integer;

pub fn evens(iter: impl Iterator<item =="" i32="">) -> impl Iterator<item =="" i32=""> {
    iter.filter(|x| *x % 2 == 0)
}

pub fn evens_generic<t: integer="">(iter: impl Iterator<item =="" t="">) -> impl Iterator<item =="" t=""> {
    iter.filter(|x| *x % 2 == 0)
}

fn main() {
    let nums = vec!(1, 2, 3, 4, 5);
    let filtered = evens_generic(nums.into_iter());
    println!("{}", filtered.format(" "));
}

Obtengo el error del compilador:

error[E0308]: tipos no coinciden
 --> src/main.rs:9:26
  |
8 | pub fn evens_generic<t: integer="">(iter: impl Iterator<item =="" t="">) -> impl Iterator<item =="" t=""> {
  |                      - este parámetro de tipo
9 |     iter.filter(|x| *x % 2 == 0)
  |                          ^ se esperaba el parámetro de tipo `T`, se encontró un entero
  |
  = nota: se esperaba el parámetro de tipo `T`
                se encontró el tipo `{integer}`

Entiendo que los traits que agrego solo limitarán a los tipos que implementan ciertas funciones y no al tipo en sí. Pero hubiera esperado que, al limitarlo a Integer, pudiera convertir el parámetro de la función del módulo al tipo T.

Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema con la función evens_generic es que el operador de módulo % no está implementado para todos los tipos que implementan el rasgo Integer. Específicamente, el operador de módulo requiere que ambos operandos sean del mismo tipo, y en este caso, un operando es de tipo T (el parámetro de tipo genérico) y el otro es de tipo i32 (el literal entero 2).

    Para solucionar esto, necesitamos asegurarnos de que ambos operandos del operador de módulo sean del mismo tipo. Una forma de hacer esto es utilizar el rasgo num::cast::AsPrimitive para convertir el literal entero 2 al tipo T. Aquí está la función evens_generic modificada:

    use itertools::Itertools;
    use num::{Integer, NumCast};
    use num::cast::AsPrimitive;
    
    pub fn evens_generic<t>(iter: impl Iterator<item =="" t="">) -> impl Iterator<item =="" t="">
    where
        T: Integer + NumCast + Copy,
    {
        iter.filter(|x| *x % T::from(2).unwrap().as_()).copied()
    }
    
    fn main() {
        let nums = vec!(1, 2, 3, 4, 5);
        let filtered = evens_generic(nums.into_iter());
        println!("{}", filtered.format(" "));
    }
    

    En esta versión de evens_generic, hemos agregado dos rasgos adicionales al parámetro de tipo genérico T: NumCast y Copy. NumCast es necesario para convertir el literal entero 2 al tipo T, y Copy es necesario porque usamos el método copied() en el iterador para evitar problemas de tiempo de vida.

    Dentro del cierre filter, primero convertimos el literal entero 2 al tipo T usando T::from(2).unwrap(). Luego utilizamos el rasgo AsPrimitive para convertir el resultado de T::from(2).unwrap() al mismo tipo que x usando el método as_(). Finalmente, podemos utilizar el operador de módulo % con dos operandos del mismo tipo para filtrar los números pares.

    Con estas modificaciones, la función evens_generic debería funcionar ahora con cualquier tipo que implemente los rasgos necesarios.

Comments are closed.