Rust:使用泛型特征作为特征参数

Mar*_*cel 3 traits rust

如何在 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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

GameState是一个泛型到 a 的特性Game,并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
Run Code Online (Sandbox Code Playgroud)

但在我看来,我Gexpand功能和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
        }
    }

}


Run Code Online (Sandbox Code Playgroud)

Frx*_*rem 6

impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

问题是它G不受约束,所以在这个块中可能有多个(可能是冲突的)实现,因为GS可能实现GameState<G>了 multiple G。参数G不明确。


如果您想保持GameState<G>能够为 multiple 实现G,您应该将约束从impl块移动到方法:

impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如果只想GameState为单个 实现G,则应创建G关联类型 ofGameState而不是泛型类型参数:

// 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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*all 5

G不能根据 的类型来确定的具体类型TreeNode<GS>;只有在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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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,
}
Run Code Online (Sandbox Code Playgroud)

然后,一旦您考虑了额外的类型参数,您的原始实现块应该按编写的方式工作。