gpt4 book ai didi

rust - 在结构中存储特征对象

转载 作者:行者123 更新时间:2023-11-29 08:00:36 27 4
gpt4 key购买 nike

I'm working on a parser 有一堆不同的节点(现在大约有 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();

类似于此测试 is in the tests 的内容。

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

最佳答案

错误来自于 Node 上的 get_kind 方法期望值是 self,而不是 &self。按值传递 self 意味着该方法获得对象的所有权(因此丢弃它和方法的结尾),这在这里不是必需的。一般来说,你应该默认使用&self,然后如果你需要改变对象,改为&mut self,或者如果你需要改变self使用该对象(例如,因为您需要将对象的字段之一移动到别处而您不想克隆它)。

顺便说一下,我注意到你实现了 ToString为你的结构。但是,ToString 的文档说:

This trait is automatically implemented for any type which implements the Display trait. As such, ToString shouldn't be implemented directly: Display should be implemented instead, and you get the ToString implementation for free.


除了使用 trait,您还可以考虑使用 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 才能访问任何变体的数据。

如果你有只适用于一个特定变体的方法(例如,一种方法只对 List 有意义),使用 enum 方法,你会能够在任何类型的节点上调用它,因为每个 enum 变体没有不同的类型(从 Rust 1.6 开始;有关于引入此功能的讨论)。但是,您的代码大部分时间都可能在抽象的 Node 上工作,并且无论如何在调用该方法之前您都必须验证您拥有的节点类型,因此您不妨将其移动逻辑直接进入这些方法。

关于rust - 在结构中存储特征对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35233181/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com