rust - ¿Cómo implemento un rasgo que no poseo para un tipo que no poseo?
traits (2)
Esto haría posible cosas como
vec << 4
, lo que sería un buen azúcar paravec.push(4)
.
Aunque se puede hacer, generalmente es una mala idea implementar un operador con una semántica inesperada.
Aquí hay un ejemplo de cómo se puede hacer esto:
use std::ops::Shl;
struct BadVec<T>(Vec<T>);
impl<T> Shl<T> for BadVec<T> {
type Output = BadVec<T>;
fn shl(mut self, elem: T) -> Self::Output {
self.0.push(elem);
self
}
}
fn main() {
let mut v = BadVec(vec![1, 2, 3]);
v = v << 4;
assert_eq!(vec![1, 2, 3, 4], v.0)
}
Si implementas Deref
( DerefMut
):
use std::ops::{Deref, DerefMut};
impl<T> Deref for BadVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for BadVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
Puedes llamar a los métodos de Vec
:
fn main() {
let mut v = BadVec(vec![1, 2, 3]);
v = v << 4;
v.truncate(2);
assert_eq!(2, v.len());
}
Eche un vistazo a la caja newtype_derive
, puede generar un código repetitivo para usted.
Quería implementar el rasgo Shl
para Vec
, el código está abajo. Esto haría posible cosas como vec << 4
, lo que sería un buen azúcar para vec.push(4)
.
use std::ops::Shl;
impl<T> Shl<T> for Vec<T> {
type Output = Vec<T>;
fn shl(&self, elem: &T) -> Vec<T> {
self.push(*elem);
*self
}
}
fn main() {
let v = vec![1, 2, 3];
v << 4;
}
La compilación falla con el siguiente error:
no puede proporcionar una implementación de extensión donde tanto el rasgo como el tipo no estén definidos en esta caja [E0117]
o
el parámetro de tipo
T
debe usarse como el parámetro de tipo para algún tipo local (por ejemplo,MyStruct<T>
); solo se pueden implementar rasgos definidos en la caja actual para un parámetro de tipo [E0210]
Como lo entiendo, tendría que parchear el stdlib, más específicamente las collections::vec
crate. ¿Hay otra manera de cambiar este código para compilar con éxito?
Si bien no puede hacerlo exactamente, la solución habitual es simplemente envolver el tipo que desee en su propio tipo e implementar el rasgo en eso.
use somecrate::FooType;
use somecrate::BarTrait;
struct MyType(FooType);
impl BarTrait for MyType {
fn bar(&self) {
// use `self.0` here
}
}