Как реализовать черту, которой я не владею, для типа, которым я не владею?

rust traits

3152 просмотра

2 ответа

Я хотел реализовать эту Shlчерту Vec, код ниже. Это сделало бы такие вещи vec << 4возможными, что было бы неплохо для сахара 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;
}

Компиляция завершается со следующей ошибкой:

не может обеспечить реализацию расширения, в которой в этом ящике не определены ни признак, ни тип [E0117]

или же

параметр типа Tдолжен использоваться в качестве параметра типа для некоторого локального типа (например MyStruct<T>); только параметры, определенные в текущем ящике, могут быть реализованы для параметра типа [E0210]

Насколько я понимаю, мне пришлось бы залатать stdlib, а точнее collections::vecящик. Есть ли другой способ изменить этот код для успешной компиляции?

Автор: le_me Источник Размещён: 12.11.2019 09:39

Ответы (2)


35 плюса

Решение

Хотя вы не можете сделать это точно, обычный обходной путь заключается в том, чтобы просто обернуть нужный вам тип в свой собственный тип и реализовать в нем черту.

use somecrate::FooType;
use somecrate::BarTrait;

struct MyType(FooType);

impl BarTrait for MyType {
    fn bar(&self) {
        // use `self.0` here
    }
}
Автор: Luqman Размещён: 20.08.2014 10:10

12 плюса

Это сделало бы такие вещи vec << 4возможными, что было бы неплохо для сахара vec.push(4).

Хотя это может быть сделано, обычно плохая идея реализовать оператор с неожиданной семантикой.

Вот пример того, как это можно сделать:

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)
}

Если вы реализуете 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
    }
}

Вы можете вызвать Vecметоды:

fn main() {
    let mut v = BadVec(vec![1, 2, 3]);
    v = v << 4;
    v.truncate(2);
    assert_eq!(2, v.len());
}

Взгляните на newtype_deriveящик, он может сгенерировать некоторый шаблонный код для вас.

Автор: malbarbo Размещён: 24.06.2016 04:35
Вопросы из категории :
32x32