E0369: Operador Não Pode Ser Aplicado no Rust

Como resolver o erro E0369 do Rust: operador binário não pode ser aplicado ao tipo. Aprenda a implementar traits de operadores como Add, Sub, Mul para seus tipos.

E0369: Operador Não Pode Ser Aplicado

O erro E0369 ocorre quando você tenta usar um operador binário (como +, -, *, ==) em tipos que não implementam o trait correspondente. No Rust, operadores são definidos por traits — e tipos customizados precisam implementá-los explicitamente.

A Mensagem de Erro

error[E0369]: binary operation `+` cannot be applied to type `Vetor2D`
 --> src/main.rs:10:22
  |
10 |     let soma = v1 + v2;
   |                -- ^ -- Vetor2D
   |                |
   |                Vetor2D
   |
   = note: an implementation of `std::ops::Add` is missing for `Vetor2D`

Outra variação com comparação:

error[E0369]: binary operation `==` cannot be applied to type `Produto`
 --> src/main.rs:8:16
  |
8 |     if item1 == item2 {
  |        ----- ^^ ----- Produto
  |        |
  |        Produto
  |
  = note: an implementation of `PartialEq` is missing for `Produto`

O Que Significa

No Rust, cada operador é mapeado para um trait específico do módulo std::ops:

OperadorTrait
+std::ops::Add
-std::ops::Sub
*std::ops::Mul
/std::ops::Div
%std::ops::Rem
==, !=std::cmp::PartialEq
<, >, <=, >=std::cmp::PartialOrd
- (unário)std::ops::Neg
!std::ops::Not
<<, >>std::ops::Shl, std::ops::Shr
&, |, ^std::ops::BitAnd, BitOr, BitXor

Tipos primitivos (i32, f64, etc.) já implementam esses traits. Tipos customizados (structs, enums) precisam de implementação manual ou via #[derive].

Código com Erro

struct Vetor2D {
    x: f64,
    y: f64,
}

fn main() {
    let v1 = Vetor2D { x: 1.0, y: 2.0 };
    let v2 = Vetor2D { x: 3.0, y: 4.0 };

    // ERRO: Vetor2D não implementa Add
    let soma = v1 + v2;

    // ERRO: Vetor2D não implementa PartialEq
    let igual = v1 == v2;
}

Também acontece ao tentar operar entre tipos diferentes:

fn main() {
    let texto = String::from("Olá");
    let numero = 42;

    // ERRO: não pode somar String com i32
    let resultado = texto + numero;
}

Como Resolver

Solução 1: Usar #[derive] para Comparações

Para operadores de comparação, use derive:

#[derive(Debug, PartialEq, PartialOrd)]
struct Temperatura {
    celsius: f64,
}

fn main() {
    let t1 = Temperatura { celsius: 25.0 };
    let t2 = Temperatura { celsius: 30.0 };

    println!("Iguais: {}", t1 == t2);   // PartialEq
    println!("Menor: {}", t1 < t2);     // PartialOrd
}

Solução 2: Implementar Traits de Operadores Manualmente

Para +, -, * e outros operadores aritméticos, implemente o trait correspondente:

use std::ops::Add;

#[derive(Debug, Clone, Copy)]
struct Vetor2D {
    x: f64,
    y: f64,
}

impl Add for Vetor2D {
    type Output = Vetor2D;

    fn add(self, outro: Vetor2D) -> Vetor2D {
        Vetor2D {
            x: self.x + outro.x,
            y: self.y + outro.y,
        }
    }
}

fn main() {
    let v1 = Vetor2D { x: 1.0, y: 2.0 };
    let v2 = Vetor2D { x: 3.0, y: 4.0 };
    let soma = v1 + v2;
    println!("{:?}", soma); // Vetor2D { x: 4.0, y: 6.0 }
}

Implementando múltiplos operadores:

use std::ops::{Add, Sub, Mul, Neg};

#[derive(Debug, Clone, Copy, PartialEq)]
struct Vetor2D {
    x: f64,
    y: f64,
}

impl Sub for Vetor2D {
    type Output = Vetor2D;
    fn sub(self, outro: Vetor2D) -> Vetor2D {
        Vetor2D {
            x: self.x - outro.x,
            y: self.y - outro.y,
        }
    }
}

impl Mul<f64> for Vetor2D {
    type Output = Vetor2D;
    fn mul(self, escalar: f64) -> Vetor2D {
        Vetor2D {
            x: self.x * escalar,
            y: self.y * escalar,
        }
    }
}

impl Neg for Vetor2D {
    type Output = Vetor2D;
    fn neg(self) -> Vetor2D {
        Vetor2D {
            x: -self.x,
            y: -self.y,
        }
    }
}

fn main() {
    let v = Vetor2D { x: 1.0, y: 2.0 };
    println!("Dobro: {:?}", v * 2.0);
    println!("Negativo: {:?}", -v);
}

Solução 3: Converter Tipos Antes de Operar

Quando os tipos são diferentes, converta antes:

fn main() {
    let texto = String::from("Olá, ");
    let complemento = "mundo!";

    // String + &str funciona!
    let resultado = texto + complemento;
    println!("{}", resultado);

    // Para concatenar sem mover, use format!
    let a = String::from("Olá");
    let b = String::from("mundo");
    let resultado = format!("{}, {}!", a, b);
    println!("{}", resultado);
}

Para números:

fn main() {
    let inteiro: i32 = 10;
    let decimal: f64 = 3.14;

    // ERRO: i32 + f64 não é permitido
    // let resultado = inteiro + decimal;

    // Converta primeiro:
    let resultado = f64::from(inteiro) + decimal;
    println!("{}", resultado); // 13.14
}

Dica: AddAssign, SubAssign, etc.

Para usar operadores de atribuição composta (+=, -=), implemente os traits correspondentes:

use std::ops::AddAssign;

#[derive(Debug)]
struct Contador {
    valor: i32,
}

impl AddAssign<i32> for Contador {
    fn add_assign(&mut self, rhs: i32) {
        self.valor += rhs;
    }
}

fn main() {
    let mut c = Contador { valor: 0 };
    c += 5;
    c += 3;
    println!("{:?}", c); // Contador { valor: 8 }
}

Veja Também