捕获仅在实现中使用的结构中的特征

Capturing a trait in a struct that is only used in the implementation

如何定义具有多态结构和与其相关联的特征的 struct,但特征不影响 struct 定义,仅影响实现?

此处编译器拒绝接受 Interpreter 的定义,因为 Evaluator 未被使用,但在实现中是必要的:

pub trait StateEvaluator<State> {
    fn eval(state: State, buf: &mut [u8]);
}

pub struct Interpreter<State, Evaluator> {
    state: State
}

impl<State: Default, Evaluator: StateEvaluator<State>> Interpreter<State, Evaluator> {
    pub fn new() -> Interpreter<State, Evaluator> {
        Interpreter {
            state: Default::default()
        }
    }

    pub fn eval(&self, buf: &mut [u8]) {
        Evaluator::eval(self.state, buf)
    }
}

struct 中删除它会导致 impl 版本不匹配,并出现不同的编译器错误,即期望 1 个参数并得到 2 个参数。

您可以选择几个方向:

  • 添加一个phantom data marker for Evaluator:

    use std::marker;
    
    pub trait StateEvaluator<State> {
        fn eval(state: State, buf: &mut [u8]);
    }
    
    pub struct Interpreter<State, Evaluator> {
        state: State,
        evaluator: marker::PhantomData<Evaluator>,
    }
    
    impl<State: Default + Clone, Evaluator: StateEvaluator<State>> Interpreter<State, Evaluator> {
        pub fn new() -> Interpreter<State, Evaluator> {
            Interpreter {
                state: Default::default(),
                evaluator: marker::PhantomData,
            }
        }
    
        pub fn eval(&self, buf: &mut [u8]) {
            Evaluator::eval(self.state.clone(), buf)
        }
    }
    

    这样在结构中使用泛型类型。 (请注意,我已做出将 Clone 绑定到 State 的行政决定,以便 eval 可以将 State 传递给 StateEvaluator;您可以也可以接受 &StateCopy 限制。)

  • Evaluator 泛型从类型转移到 eval 函数。这可能不是您想要的,但我会提到它。

    pub trait StateEvaluator<State> {
        fn eval(state: State, buf: &mut [u8]);
    }
    
    pub struct Interpreter<State> {
        state: State,
    }
    
    impl<State: Default + Clone> Interpreter<State> {
        pub fn new() -> Interpreter<State> {
            Interpreter {
                state: Default::default(),
            }
        }
    
        pub fn eval<Evaluator: StateEvaluator<State>>(&self, buf: &mut [u8]) {
            Evaluator::eval(self.state.clone(), buf)
        }
    }
    

类型参数Evaluator被称为phantom type because it is not used in the type definition. Rust used to allow such code to compile, but a change earlier this year related to variance是非法的。相反,您必须使用类型参数。

要保留其幽灵性质,您可以使用 "marker" 之类的 PhantomData。这是一种由编译器解释的特殊类型。

让您的代码正常工作很容易。只需添加一个使用您的幻像类型参数的 PhantomData 成员:

use std::marker::PhantomData;

pub struct Interpreter<State, Evaluator> {
    state: State,
    _marker: PhantomData<Evaluator>,
}

然后稍微调整结构:

Interpreter {
    state: Default::default(),
    _marker: PhantomData,
}

类型推断会自动填充 PhantomData 的类型参数。