tag ejemplos div attribute generics rust

generics - ejemplos - title html attribute



¿Cómo requiero que un tipo genérico implemente una operación como Agregar, Sub, Mul o Div en una función genérica? (2)

Analicemos un poco su ejemplo:

fn cube<T: Mul>(x: T) -> T { let a = x * x; let b = a * x; b }

¿Cuáles son los tipos de b ? En este caso, el tipo de a es <T as std::ops::Mul>::Output - ¿le suena familiar el mensaje de error? Entonces, estamos tratando de multiplicar ese tipo por x nuevamente, ¡pero no hay garantía de que Output pueda multiplicarse por nada!

Hagamos lo más simple y digamos que T * T necesita dar como resultado una T :

fn cube<T: Mul<Output = T>>(x: T) -> T { x * x * x }

Desafortunadamente, esto da dos errores similares:

error[E0382]: use of moved value: `x` --> src/lib.rs:6:9 | 6 | x * x * x | - ^ value used here after move | | | value moved here | = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait

Lo cual se debe a que el rasgo Mul toma argumentos por valor , por lo que agregamos la Copy para poder duplicar los valores.

También cambié a la cláusula where ya que me gusta más y es difícil tener tanto en línea:

fn cube<T>(x: T) -> T where T: Mul<Output = T> + Copy { x * x * x }

Ver también:

  • ¿Cómo implemento el rasgo Agregar para una referencia a una estructura?
  • ¿Cómo escribir un rasgo limitado para agregar dos referencias de un tipo genérico?

Estoy tratando de implementar una función genérica en Rust donde el único requisito para el argumento es que la operación de multiplicación debe definirse. Estoy tratando de implementar un "poder" genérico, pero iré con una función de cube más simple para ilustrar el problema:

use std::ops::Mul; fn cube<T: Mul>(x: T) -> T { x * x * x } fn main() { println!("5^3 = {}", cube(5)); }

Al compilar me sale este error:

error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output` --> src/main.rs:4:5 | 4 | x * x * x | ^^^^^^^^^ | = note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output`

¿Qué significa esto? ¿Elegí el rasgo equivocado? ¿Cómo puedo resolver esto?


El límite T: Mul no implica que el resultado del operador binario sea también del tipo T El tipo de resultado es un tipo asociado de este rasgo: Output .

El otro problema es que antes de Rust 1.0 los rasgos del operador cambiaron de paso por referencia a paso por valor. En el código genérico, esto puede ser un poco molesto (al menos por ahora) porque estos operadores consumen sus operandos a menos que también requiera que los tipos sean Copy .

Solo para completar (en caso de que no desee solicitar una Copy ), permítame agregar información sobre una posible dirección alternativa.

Por el bien del código genérico, se alienta a los autores de "tipos numéricos" a proporcionar implementaciones adicionales no consumidoras de estos rasgos de operador para que no necesite Copy o Clone . Por ejemplo, la biblioteca estándar ya proporciona las siguientes implementaciones:

f64 implements Mul< f64> f64 implements Mul<&f64> &f64 implements Mul< f64> &f64 implements Mul<&f64>

Cada una de estas implementaciones tiene f64 como tipo de Output . Hacer uso de estos rasgos directamente no es bonito:

fn cube<T>(x: &T) -> T where for<''a> T: Mul<&''a T, Output = T>, for<''a, ''b> &''a T: Mul<&''b T, Output = T>, { x * x * x }

Eventualmente, podríamos obtener algunos rasgos (ligeramente) de mayor nivel, lo que reduciría el ruido. Por ejemplo: T: Mul2 podría implicar T: Mul<T> + Mul<&T> y &T: Mul<T> + Mul<&T> , pero al momento de escribir esto, el compilador Rust no parece capaz de manejar esto . Al menos no pude compilar con éxito el siguiente código:

use std::ops::Mul; pub trait Mul2 where Self: Mul<Self, Output = Self>, Self: for<''a> Mul<&''a Self, Output = Self>, for<''a> &''a Self: Mul<Self, Output = Self>, for<''a, ''b> &''a Self: Mul<&''b Self, Output = Self>, { } impl<T> Mul2 for T where T: Mul<T, Output = T>, T: for<''a> Mul<&''a T, Output = T>, for<''a> &''a T: Mul<T, Output = T>, for<''a, ''b> &''a T: Mul<&''b T, Output = T>, { } fn cube<T: Mul2>(x: &T) -> T { x * x * x } fn main() { let c = cube(&2.3); println!("Hello, world! {}", c) }

Creo que es seguro decir que las cosas mejorarán en esta área. Por ahora, la capacidad de implementar genéricamente algoritmos numéricos en Rust no es tan buena como me gustaría que fuera.