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);
}
}
}
}
GameState
是 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
但在我看来,我在 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);
}
}
}
}
如何在 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);
}
}
}
}
GameState
是 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
但在我看来,我在 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);
}
}
}
}