将特征对象存储在结构中

文森特

我正在使用具有许多不同节点的解析器(现在大约有6种节点类型,以后再介绍),而如何与节点项进行交互(所有节点都实现了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);
}

我得到像这样的借用和大小调整错误,例如:

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();

同样的事情也该测试是在测试中

我应该如何访问特征对象,或者该方法在Rust中存在缺陷?是否可以将特征实现为特征(例如Debug)或特征?我是否Debug为嵌入的每个结构手动实现Node

弗朗西斯·加涅

这个错误来自一个事实,即get_kind在方法Node希望self通过值,而不是&selfself通过值传递意味着该方法获得了对象的所有权(因此删除了该对象并终止了该方法的结尾),在此无需这样做。通常,您应该&self默认使用,然后更改为&mut self是否需要使对象突变,或者self是否需要使用该对象(例如,因为您需要将对象的字段之一移至其他位置,并且您不想克隆它)。

顺便说一句,我注意到您ToString为您的结构实现了。但是,文档中ToString指出:

对于实现该Display特征的任何类型,该特征都会自动实现因此,ToString不应该直接实现:Display应该实现,您可以ToString免费获得实现。


除了使用特征以外,您还可以考虑使用enum,尤其是如果节点的类型事先已知并且不需要扩展性时。另外,如果以后需要确定节点的类型,则使用enum(执行模式匹配)会更自然

看来您需要所有节点类型都具有kindposition属性。根据您将如何使用这些节点,可能会发现用这些字段以及一个用于特定类型字段的枚举来定义结构更有用。

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才能访问任何变量的数据。

如果您有仅适用于一个特定变体的方法(例如,仅对有意义Listenum方法),则使用该方法,您将能够在任何类型的节点上调用它,因为每种enum变体没有不同的类型(从Rust 1.6开始;有关引入此功能的讨论)。但是,您的代码可能Node大多数时候都可以在抽象上运行,并且无论如何都必须在调用该方法之前验证您拥有的节点类型,因此您最好将该逻辑直接移到那些方法中。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章