I'm working on a parser有一堆不同的节点(现在约6种节点,后来更多),我对如何与节点项进行交互有点迷失(所有节点实现{{1} } trait)所以我需要在任何地方使用Node
。
Box<Node>
看起来像:
ListNode
但是我无法派生pub struct ListNode {
kind: NodeKind,
position: usize,
pub nodes: Vec<Box<Node>>
}
,因为Clone
没有实现它,每当我试图获得测试中的那种节点时就像这样:
Node
我得借用和调整错误,例如:
#[test]
fn test_plain_string() {
let mut parser = Parser::new("plain_string", "Hello world");
parser.parse();
assert_eq!(1, parser.root.nodes.len());
let ref node = parser.root.nodes[0];
let kind = node.get_kind();
assert_eq!(kind, NodeKind::Text);
}
类似于此测试is in the tests的内容。
我应该如何访问特征对象或者这种方法在Rust中存在缺陷?
是否可以将特征实现到特征(如src/parser.rs:186:20: 186:24 error: cannot move out of borrowed content [E0507]
src/parser.rs:186 let kind = node.get_kind();
^~~~
src/parser.rs:186:20: 186:24 error: cannot move a value of type nodes::Node + 'static: the size of nodes::Node + 'static cannot be statically determined [E0161]
src/parser.rs:186 let kind = node.get_kind();
)到特征,或者我是否为嵌入Debug
的每个结构手动实施Debug
?
答案 0 :(得分:2)
错误来自于get_kind
上的Node
方法按值self
而不是&self
。{按值传递self
意味着该方法获取对象的所有权(因此删除它和方法的结尾),这在此不是必需的。通常,默认情况下应使用&self
,如果需要改变对象,则更改为&mut self
;如果需要使用对象,则更改为self
(例如,因为您需要移动其他地方的一个对象字段,你不想克隆它。)
顺便说一下,我注意到你为你的结构实现了ToString
。但是,ToString
的文档说:
此特征会自动为任何实现的类型实现
Display
特征。因此,ToString
不应该实现 直接:Display
应该实现,而你得到了。ToString
enum
免费实施。
您也可以考虑使用enum
而不是使用特征,尤其是如果事先知道节点类型并且您不需要可扩展性。此外,如果稍后您需要确定节点的类型,那么使用kind
(仅进行模式匹配)会更自然。
您似乎需要所有节点类型都具有position
和struct Node {
//kind: NodeKind, // redundant!
position: usize,
specific: SpecificNode,
}
enum SpecificNode {
List(Vec<Box<Node>>),
Text(String),
VariableBlock(Box<Node>),
Identifier(String),
Int(i32),
Float(f32),
Bool(bool),
}
属性。根据您将如何使用这些节点,您可能会发现使用这些字段定义结构以及特定于类型字段的枚举更有用。
SpecificNode
嗯,NodeKind
枚举看起来很像你的kind
枚举,不是吗?实际上,specific
字段变得多余,因为您可以通过查看self
字段的变体来确定类型。
现在,不是在每种类型的节点上单独实现方法,而是只定义它们一次,尽管每个方法通常需要模式匹配List
才能访问任何变体的数据。
如果您的方法仅适用于一个特定变体(例如,只对enum
有意义的方法),使用enum
方法,您可以在任何方法上调用它节点的类型,因为每个Node
变体没有不同的类型(从Rust 1.6开始;有关于引入此功能的讨论)。但是,您的代码很可能在大多数情况下都在抽象ffmpeg -i in.mp4 -i in.srt -c copy -disposition:s:0 default out.mkv
上运行,并且您无需在调用方法之前验证您拥有的节点类型,因此您不妨将该逻辑直接移入那些方法。