[英]Rust: Using a generic trait as a trait parameter
How can I use related generic types in Rust?如何在 Rust 中使用相关的泛型类型?
Here's what I've got (only the first line is giving me trouble):这是我得到的(只有第一行给我带来了麻烦):
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
is a trait that is generic to a Game
, and self.data
implements GameState<Game>
of this type. GameState
是Game
通用的 trait, self.data
实现了这种类型的GameState<Game>
。 The compiler tells me编译器告诉我
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
but it seems to me like I'm constraining G
both in the expand
function, and in the fact that G
needs to belong to GS
.但在我看来,我在
expand
函数中限制了G
,事实上G
需要属于GS
。 I would really appreciate any help.我真的很感激任何帮助。
Edit: Here are some more definitions as of now编辑:截至目前,这里有更多定义
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
}
}
}
impl<G, GS> TreeNode<GS> where G: Game, GS: GameState<G>{
// ...
}
The problem is that G
is not constrained, so there may be multiple (possibly conflicting) implementations in this block, since GS
maybe implement GameState<G>
for multiple G
.问题是
G
不受约束,因此该块中可能有多个(可能是冲突的)实现,因为GS
可能为多个G
实现GameState<G>
。 The parameter G
is ambiguous.参数
G
不明确。
If you want to keep GameState<G>
able to be implemented for multiple G
, you should move the constraints from the impl
block to the method instead:如果您想让
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);
}
}
}
}
If you only want GameState
to be implemented for a single G
, you should make G
an associated type of GameState
instead of a generic type parameter:如果您只想为单个
G
实现GameState
,则应使G
成为GameState
的关联类型而不是泛型类型参数:
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);
}
}
}
}
The concrete type of G
cannot be detemined based on the type of TreeNode<GS>
;根据
TreeNode<GS>
的类型无法确定G
的具体类型; it is only known when expand
is called.只有在调用
expand
时才知道。 Note that expand
could be called twice with different types for G
.请注意,可以使用
G
不同类型调用expand
两次。
You can express this by constraining the type parameters for the method instead of the entire implementation block:您可以通过约束方法的类型参数而不是整个实现块来表达这一点:
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);
}
}
}
}
If it should not be possible for expand
to be called with different G
s then this is a problem of your modeling.如果不能用不同的
G
调用expand
,那么这是您的建模问题。 Another way to fix this is to ensure that the type of G
is known for all TreeNode
seg:解决此问题的另一种方法是确保所有
TreeNode
段都知道G
的类型:
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,
}
And then your original implementation block should work as written, once you account for the extra type parameter.然后,一旦您考虑了额外的类型参数,您的原始实现块应该按编写的方式工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.