En Rust, la sobrecarga de operadores permite definir el comportamiento de operadores aritméticos, lógicos y de comparación para tipos de datos personalizados. A diferencia de otros lenguajes que permiten la sobrecarga de cualquier función, Rust utiliza un sistema basado en traits definidos en el módulo std::ops. Esto garantiza que el comportamiento de los operadores sea predecible y siga las reglas de tipado del compilador.
Para implementar la sobrecarga, se deben implementar traits específicos como Add para el operador +, Sub para -, Mul para *, Div para /, y Neg para la negación unaria -x. También existen traits para el acceso a índices (Index e IndexMut) y para la dereferencia (Deref).
El uso de estos traits es ideal cuando se crean tipos que representan entidades matemáticas (como vectores, matrices o números complejos) o estructuras de datos que requieren una sintaxis natural (como contenedores). Sin embargo, es vital mantener la coherencia semántica: sobrecargar un operador para realizar una acción que no tenga relación intuitiva con el símbolo (por ejemplo, usar + para borrar un elemento de una lista) confunde al desarrollador y rompe el principio de menor sorpresa.
use std::ops::{Add, Sub, Neg};
// Definición de una estructura para representar un vector en 2D
#[derive(Debug, PartialEq)]
struct Vector2D {
x: f64,
y: f64,
}
// Implementación de la suma: Vector2D + Vector2D = Vector2D
impl Add for Vector2D {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
// Implementación de la resta: Vector2D - Vector2D = Vector2D
impl Sub for Vector2D {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
// Implementación de la negación unaria: -Vector2D = Vector2D (con signos invertidos)
impl Neg for Vector2D {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
}
}
}
fn main() {
let v1 = Vector2D { x: 10.0, y: 20.0 };
let v2 = Vector2D { x: 5.0, y: 5.0 };
// Uso de la sobrecarga de suma (+)
let suma = v1 + v2;
// Uso de la sobrecarga de resta (-)
let resta = v1 - v2;
// Uso de la sobrecarga de negación unaria (-)
let negado = -v1;
println!("Vector 1: {:?}", v1);
println!("Vector 2: {:?}", v2);
println!("Suma: {:?}", suma);
println!("Resta: {:?}", resta);
println!("Negado de v1: {:?}", negado);
}
Explicación del Código
– use std::ops::{Add, Sub, Neg};: Importamos los traits necesarios para sobrecargar la suma, la resta y la negación.
– struct Vector2D { x: f64, y: f64 }: Definimos nuestra estructura con dos campos de tipo f64. Usamos #[derive(Debug, PartialEq)] para poder imprimir la estructura y compararla.
– impl Add for Vector2D: Implementamos el trait Add. El tipo asociado type Output = Self; especifica que el resultado de la operación será otro Vector2D.
– fn add(self, rhs: Self) -> Self: El método add recibe self (el operando de la izquierda) y rhs (Right Hand Side, el operando de la derecha). Sumamos sus componentes x e y correspondientes.
– impl Sub for Vector2D: Implementamos Sub para permitir la operación v1 - v2. Al igual que en Add, el operando derecho se denomina rhs.
– impl Neg for Vector2D: Implementamos Neg para el operador unario. A diferencia de los anteriores, neg no recibe un segundo operando, solo self.
– En main, la expresión v1 + v2 es una llamada al método add de v1 pasando a v2 como argumento, lo que permite una sintaxis limpia y matemática.
N° 119