Как мне «заставить» структуры реализовать те же черты? - PullRequest
0 голосов
/ 04 июня 2018

У меня есть следующее:

pub struct OpBStruct {
    title: String,
    output_vale: i32,
}

impl OpBStruct {
    pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
        OpBStruct {
            title: in_title,
            output_vale: in_output_vale,
        }
    }
}

pub struct OpCStruct {
    title: String,
    another_value: String,
    output_vale: i32,
}

impl OpCStruct {
    pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
        OpCStruct {
            title: in_title,
            another_value: in_another_value,
            output_vale: in_output_vale,
        }
    }
}

impl A {
    pub fn new_A(in_name: String, in_operator: Op) -> A {
        A {
            name: in_name,
            operator: in_operator,
        }
    }
}

pub enum Op {
    OpB(OpBStruct),
    OpC(OpCStruct),
}

pub struct A {
    name: String,
    operator: Op,
}

impl A {
    pub fn new_A(in_name: String, in_operator: Op) -> A {
        A {
            name: in_name,
            operator: in_operator,
        }
    }
}

Точная структура OpBStruct и OpCStruct произвольна и может быть чем угодно.

Как мне убедиться, OpBStruct иOpCStruct реализовать определенную черту?

trait OpTrait {    
    pub fn get_op_output(&self) -> i32;
}

Я думал о создании своего рода функции конструктора, которая проверяла бы требование черты OpTrait, и это был бы единственный способ создать экземпляр Op, но каждому оператору требуются разные параметры инициализации, и нет способа указать переменное число входов для функции в Rust.

Что-то подобное не работает, потому что нет способа ввода параметров инициализации:

pub fn new_op<T: OpTrait>(operator: T) {
    //  --snip--
}

Я думал о том, чтобы каким-то образом использовать метод new_A, реализованный в A, чтобы проверить, реализовал ли признак in_operator, но я тоже не уверен, как это сделать.

Каков правильный шаблон для этого?Если их нет, я могу просто реализовать эту черту для каждого Op без какого-либо интерфейса вокруг него.

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Я бы также порекомендовал написать тест, однако вы можете написать функцию, которая является общей для типа, но не имеет аргументов:

struct X {}

trait Y {
    fn yo();
}

fn is_y<T: Y>(){}

Затем вы можете добавить следующую строку для проверки

is_y::<X>();

, который будет компилироваться, только если X реализует Y.

0 голосов
/ 07 июня 2018

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

Если в остальной части кода вы указали входные данные о функциях для функций, это может произойти довольно естественно без модульного теста.Преимущество этого теста в том, что у вас есть возможность явно проверить некоторый инвариант реализации черты.

struct A {
    val: u8,
}


struct B {
    val: u32,
}

trait ExpandToU64 {
    fn to_u64(&self) -> u64;
}

impl ExpandToU64 for A {
    fn to_u64(&self) -> u64
    {
        self.val as u64
    }
}

fn trait_tester<E>(a: E)
    where E: ExpandToU64
{
    // the utility function doesn't have to even use the trait...
    // but you probably want to exercise the logic a bit
    //let v = a.to_u64();
    let v = 24u64;
    println!("{:?}", v);
}

#[test]
fn test_needs_trait_ExpandToU64() {
    let a = A { val:1 };
    trait_tester(a);

    let b = B { val:2 };
    trait_tester(b);
    // This fails with a compile error
    //  "the trait `ExpandToU64` is not implemented for `B`"
}
...