我怎么强迫'结构实现相同的特征?

时间:2018-06-04 09:19:08

标签: rust traits

我有以下内容:

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

OpBStructOpCStruct的确切结构是任意的,可以是任何内容。

如何确保OpBStructOpCStruct实现某种特质?

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

我考虑过制作一种检查OpTrait特征要求的构造函数,这是创建Op实例的唯一方法,但是每个运算符都需要不同的初始化参数。 #39;无法为Rust中的函数指定可变数量的输入。

这样的事情不起作用,因为无法输入初始化参数:

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

我想过以某种方式使用在new_A上实施的A方法来检查in_operator是否已经实现了这一特性,但我也不确定如何做到这一点。

这是什么样的正确模式?如果没有,我可以为每个Op实现特征,而不是它周围的界面。

2 个答案:

答案 0 :(得分:1)

我还建议编写一个测试,但是你可以编写一个函数,该函数在类型上是通用的,但不带参数:

struct X {}

trait Y {
    fn yo();
}

fn is_y<T: Y>(){}

然后你可以添加以下行来进行检查

is_y::<X>();

仅在X实现Y时才会编译。

答案 1 :(得分:0)

使用单元测试将是一种相当简单的方法来强制您希望在结构上使用给定的特征。您可以通过隐式测试代码来完成,但是这样做的小实用程序功能可以更清楚地表达意图。

如果你已经在其余代码中指出了函数的特征输入,那么在没有单元测试的情况下它可能会相当自然地出现。该测试的优点是让您有机会明确检查特征实现的某些不变量。

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`"
}