Rust:使用通用特征作为特征参数

Rust: Using a generic trait as a trait parameter

如何在 Rust 中使用相关的泛型类型?

这是我得到的(只有第一行给我带来了麻烦):

impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
    pub fn expand(&mut self, game: &G){
        if !self.expanded{
            let child_states = self.data.generate_children(game);
            for state in child_states{
                self.add_child_with_value(state);
            }
        }
    }
}

GameStateGame 的通用特征,self.data 实现了这种类型的 GameState<Game>。编译器告诉我

error[E0207]: the type parameter `G` is not constrained by the impl trait, self type, or predicates
  --> src/mcts.rs:42:6
   |
42 | impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
   |      ^ unconstrained type parameter

error: aborting due to previous error

但在我看来,我在 expand 函数中限制了 G,事实上 G 需要属于 GS。如果有任何帮助,我将不胜感激。

编辑: 以下是截至目前的更多定义

trait GameState<G: Game>: std::marker::Sized + Debug{
    fn generate_children(&self, game: &G) -> Vec<Self>;
    fn get_initial_state(game: &G) -> Self;
}

trait Game{}

struct TreeNode<S> where S: Sized{
    parent: *mut TreeNode<S>,
    expanded: bool,
    pub children: Vec<TreeNode<S>>,
    pub data: S,
    pub n: u32
}

impl<S> TreeNode<S>{
    pub fn new(data: S) -> Self{
        TreeNode {
            parent: null_mut(),
            expanded: false,
            children: vec![],
            data,
            n: 0
        }
    }

    pub fn add_child(&mut self, mut node: TreeNode<S>){
        node.parent = self;
        self.children.push(node);
    }

    pub fn add_child_with_value(&mut self, val: S){
        let new_node = TreeNode::new(val);
        self.add_child(new_node);
    }

    pub fn parent(&self) -> &Self{
        unsafe{
            &*self.parent
        }
    }

}


无法根据TreeNode<GS>的类型判断G的具体类型;只有在调用 expand 时才知道。请注意,expand 可以使用 不同的 类型调用两次 G

您可以通过约束方法的类型参数而不是整个实现块来表达这一点:

impl<GS> TreeNode<GS> {
    pub fn expand<G>(&mut self, game: &G)
    where
        G: Game,
        GS: GameState<G>,
    {
        if !self.expanded {
            let child_states = self.data.generate_children(game);
            for state in child_states {
                self.add_child_with_value(state);
            }
        }
    }
}

如果 expand 不能用不同的 G 调用,那么这是您的建模问题。解决此问题的另一种方法是确保 G 的类型对于所有 TreeNode 都是已知的。例如:

struct TreeNode<G, S>
where
    S: Sized,
{
    parent: *mut TreeNode<G, S>,
    expanded: bool,
    pub children: Vec<TreeNode<G, S>>,
    pub data: S,
    pub n: u32,
}

然后,一旦您考虑了额外的类型参数,您的原始实现块就应该像写的那样工作。

impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
    // ...
}

问题是 G 不受约束,因此此块中可能有多个(可能冲突的)实现,因为 GS 可能为多个 [=13] 实现 GameState<G> =].参数G有歧义。


如果你想保持 GameState<G> 能够为多个 G 实现,你应该从 impl 块中移动约束改为方法:

// note: G is now a type parameter of the method, not the impl block, which is fine
impl<GS> TreeNode<GS> {
    pub fn expand<G>(&mut self, game: &G) where G: Game, GS: GameState<G> {
        if !self.expanded{
            let child_states = self.data.generate_children(game);
            for state in child_states{
                self.add_child_with_value(state);
            }
        }
    }
}

如果您只想为单个 G 实现 GameState,您应该使 G 成为 [= 的关联类型21=] 而不是泛型类型参数:

trait GameState: std::marker::Sized + Debug {
    type G: Game;
    fn generate_children(&self, game: &Self::G) -> Vec<Self>;
    fn get_initial_state(game: &Self::G) -> Self;
}

// note: now G is given by the GameState implementation instead of
//       being a free type parameter
impl<GS> TreeNode<GS> where GS: GameState {
    pub fn expand(&mut self, game: &GS::G){
        if !self.expanded{
            let child_states = self.data.generate_children(game);
            for state in child_states{
                self.add_child_with_value(state);
            }
        }
    }
}