Должен ли каждый generi c в Rust реализовывать какой-то трейт, чтобы иметь «методы»? - PullRequest
0 голосов
/ 20 июня 2020

Я не контролирую A и B ниже, они взяты из библиотеки. Оба реализуют метод hello, и я хотел бы создать функцию, которая действует на оба, но я не хочу повторно использовать код. В C ++ он не проверяет, реализует ли параметр шаблона какие-либо методы, он просто проверяет, реализует ли метод в экземпляре типа. Взгляните:

pub struct A {
    x: u8,
}

impl A {
    pub fn new() -> A {
        A { x: 0 }
    }
    pub fn hello() {
        println!("hello")
    }
}

pub struct B {
    x: u8,
}

impl B {
    pub fn new() -> B {
        B { x: 1 }
    }
    pub fn hello() {
        println!("hello")
    }
}

pub fn say_hello<T>() {
    let t: T = T::new();
    t.hello();
}

fn main() {
    say_hello::<A>();
    say_hello::<B>();
}

Это не будет компилироваться, потому что в нем говорится, что T не имеет метода say_hello. Поскольку это из библиотеки, я не могу реализовать для них трейт. Так что тут я ничего не могу сделать? Мне придется продублировать код?

Обратите внимание, что это может быть известно во время компиляции, если оба типа преобразования A и B имеют метод hello. С ++ все равно.

1 Ответ

4 голосов
/ 20 июня 2020

TL; DR: да.

Шаблоны C ++ действительно отличаются от общих типов c (особенно в Rust). Первый работает путем подстановки, не копаясь в типе во время определения элемента, а только во время использования . Итак, я считаю, что в C ++ можно создать шаблонный элемент, который в то же время компилируется и не может иметь экземпляр из-за конфликтующих требований.

Это не относится к типам generi c в Rust , они проверяются, когда вы определяете общий элемент c, например, T в fn f<T>(..) {..}. Таким образом, компилятор анализирует все случаи использования типа T и его экземпляров, чтобы они использовались правильно.

В общем, да, вам нужно иметь свойство, привязанное к использованию методов типов. Что касается вашего случая, это может быть предпочтительным решением:

trait Hello {
    fn say_hello();
}

impl Hello for A {
    fn say_hello() {
        A::hello()
    }
}

impl Hello for B {
    fn say_hello() {
        B::hello()
    }
}

Если вы хотите иметь поведение, подобное шаблонам в C ++, вы можете взглянуть на макросы :

macro_rules! say_hello {
    ($t:ty) => {{
        <$t>::hello()
    }}
}

fn main() {
    say_hello!(A);
    say_hello!(B);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...