rust - Storing trait objects in structs -
i'm working on parser has bunch of different nodes (~6 node kinds right now, more later) , i'm bit lost how interact node items (all nodes implement node
trait) need use box<node>
everywhere.
listnode
looks like:
pub struct listnode { kind: nodekind, position: usize, pub nodes: vec<box<node>> }
but can't derive clone
because node
doesn't implement , whenever try example kind of node in test so:
#[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); }
i borrowing , sizing errors example:
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 value of type nodes::node + 'static: size of nodes::node + 'static cannot statically determined [e0161] src/parser.rs:186 let kind = node.get_kind();
something similar test is in tests.
how supposed access trait objects or approach flawed in rust? possible implement traits trait (like debug
) trait or have implement debug
manually each struct embedding node
?
the error comes fact get_kind
method on node
expects self
value, rather &self
. passing self
value means method takes ownership of object (and therefore drops , end of method), not necessary here. in general, should use &self
default, change &mut self
if need mutate object, or self
if need consume object (e.g. because need move 1 of object's fields elsewhere , don't want clone it).
by way, noticed implemented tostring
structs. however, documentation tostring
says:
this trait automatically implemented type implements
display
trait. such,tostring
shouldn't implemented directly:display
should implemented instead, ,tostring
implementation free.
instead of using trait, consider using enum
, if types of nodes known in advance , don't need extensibility. also, if later on need determine type of node, it'll more natural enum
(just pattern matching).
it appears need of node types have kind
, position
attribute. depending on how you're going use these nodes, might find more useful define struct these fields plus enum type-specific fields.
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), }
hmm, specificnode
enum looks lot nodekind
enum, doesn't it? in fact, kind
field becomes redundant, because can determine kind looking @ variant of specific
field.
now, instead of implementing methods separately on each type of node, define them once, though each method need pattern match self
in order access data of variant.
if have methods apply 1 particular variant (e.g. method makes sense on list
), enum
approach, you'd able invoke on type of node, there no distinct types each enum
variant (as of rust 1.6; there discussions introducing feature). however, code work on abstract node
of time, , you'd have verify kind of node have before calling method anyway, might move logic directly methods.
Comments
Post a Comment