如何在没有代码冗余的情况下表示两个真正相似的结构?
How to represent two structs that are really similar without code redundancy?
我想为我的项目创建一个小图 module。我确实需要 有向图和无向图。
如果是 C++ 或 Java,我会制作一个抽象的 class 图实现深度优先搜索、广度优先搜索和 2 children classes 定向和未定向的特定实现或特定方法。
我确实读过这本书的 OOP 部分;但是,我将如何用 trait 表示这种行为?
理想情况下,我可以像这样使用我的 mod :
use graph::{UndirectedGraph, DirectedGraph, Graph};
pub fn main() {
let g1 = Undirectedgraph::new(); // implementing Graph trait
let g2 = DirectedGraph::new(); // implementing Graph trait
g1.dfs(); // from Graph
g2.dfs(); // from Graph
g1.bfs(); // from Graph
g2.bfs(); // from Graph
let _ = g1.has_loop(); // from UndirectedGraph implementation only
let _ = g2.has_loop() // from DirectedGraph implementation only
}
所以我得到了这样的结果;如你所见
属性和 getter 仍然有很多冗余:
#[derive(Debug)]
pub struct Node {
value: i32,
}
pub trait Graph {
fn get_vertices(&self) -> &Vec<Node>;
fn print_nodes(&self) {
self.get_vertices()
.iter()
.for_each(|x| println!("{:#?}", x));
}
fn bfs(&self) {
println!("Common implementation");
}
fn dfs(&self) {
println!("Common implementation");
}
fn has_loop(&self) -> bool; // should be implemented
}
pub struct DirectedGraph {
vertices: Vec<Node>,
}
impl Graph for DirectedGraph {
fn get_vertices(&self) -> &Vec<Node> {
&(self.vertices)
}
fn has_loop(&self) -> bool {
//some weird stuff
// specific to DirectedGraph
true
}
}
pub struct UndirectedGraph {
vertices: Vec<Node>,
}
impl Graph for UndirectedGraph {
fn get_vertices(&self) -> &Vec<Node> {
&(self.vertices)
}
fn has_loop(&self) -> bool {
//some weird stuff
// specific to UndirectedGraph
true
}
}
特征无法隐式访问默认方法实现中实现类型的数据。也就是说,您不能提供访问 Self
类型的特定字段的单个特征方法实现,因为不能假定 Self
具有任何特定字段。在未来对该语言的扩展中,可能会允许使用更好的特征访问字段构造。请参阅 RFC 1546 了解其中一项提案和相关讨论。但这仍然只适用于直接现场访问。如果您需要在返回字段之前以任何方式对其进行操作,即使那样也无济于事。
目前,您需要手动为这两种类型编写 Graph
的实现,或者如果实现确实非常相似,您可以使用包含实现内容的宏并为每种类型调用一次。两次手动实施所需的重复量是否
您不能直接从特征访问数据的属性(参见 Jimmy Cuadra 回答)。然而,我们可以使用共享的 getter 和 setter,正如 kyle 评论的那样。
类似于下面代码的东西应该可以工作。
trait Graph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput;
fn dfs(&self, v: &Vertex) -> SomeOutput {
let adjacent_edges = self.adjacent_edges(v);
// ...
}
fn bfs(&self, v: &Vertex) -> SomeOutput {
let adjacent_edges = self.adjacent_edges(v);
// ...
}
}
struct UndirectedGraph { ... }
impl Graph for UndirectedGraph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput {
// ...
}
}
struct DirectedGraph { ... }
impl Graph for DirectedGraph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput {
// ...
}
}
我想为我的项目创建一个小图 module。我确实需要 有向图和无向图。
如果是 C++ 或 Java,我会制作一个抽象的 class 图实现深度优先搜索、广度优先搜索和 2 children classes 定向和未定向的特定实现或特定方法。
我确实读过这本书的 OOP 部分;但是,我将如何用 trait 表示这种行为?
理想情况下,我可以像这样使用我的 mod :
use graph::{UndirectedGraph, DirectedGraph, Graph};
pub fn main() {
let g1 = Undirectedgraph::new(); // implementing Graph trait
let g2 = DirectedGraph::new(); // implementing Graph trait
g1.dfs(); // from Graph
g2.dfs(); // from Graph
g1.bfs(); // from Graph
g2.bfs(); // from Graph
let _ = g1.has_loop(); // from UndirectedGraph implementation only
let _ = g2.has_loop() // from DirectedGraph implementation only
}
所以我得到了这样的结果;如你所见
属性和 getter 仍然有很多冗余:
#[derive(Debug)]
pub struct Node {
value: i32,
}
pub trait Graph {
fn get_vertices(&self) -> &Vec<Node>;
fn print_nodes(&self) {
self.get_vertices()
.iter()
.for_each(|x| println!("{:#?}", x));
}
fn bfs(&self) {
println!("Common implementation");
}
fn dfs(&self) {
println!("Common implementation");
}
fn has_loop(&self) -> bool; // should be implemented
}
pub struct DirectedGraph {
vertices: Vec<Node>,
}
impl Graph for DirectedGraph {
fn get_vertices(&self) -> &Vec<Node> {
&(self.vertices)
}
fn has_loop(&self) -> bool {
//some weird stuff
// specific to DirectedGraph
true
}
}
pub struct UndirectedGraph {
vertices: Vec<Node>,
}
impl Graph for UndirectedGraph {
fn get_vertices(&self) -> &Vec<Node> {
&(self.vertices)
}
fn has_loop(&self) -> bool {
//some weird stuff
// specific to UndirectedGraph
true
}
}
特征无法隐式访问默认方法实现中实现类型的数据。也就是说,您不能提供访问 Self
类型的特定字段的单个特征方法实现,因为不能假定 Self
具有任何特定字段。在未来对该语言的扩展中,可能会允许使用更好的特征访问字段构造。请参阅 RFC 1546 了解其中一项提案和相关讨论。但这仍然只适用于直接现场访问。如果您需要在返回字段之前以任何方式对其进行操作,即使那样也无济于事。
目前,您需要手动为这两种类型编写 Graph
的实现,或者如果实现确实非常相似,您可以使用包含实现内容的宏并为每种类型调用一次。两次手动实施所需的重复量是否
您不能直接从特征访问数据的属性(参见 Jimmy Cuadra 回答)。然而,我们可以使用共享的 getter 和 setter,正如 kyle 评论的那样。
类似于下面代码的东西应该可以工作。
trait Graph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput;
fn dfs(&self, v: &Vertex) -> SomeOutput {
let adjacent_edges = self.adjacent_edges(v);
// ...
}
fn bfs(&self, v: &Vertex) -> SomeOutput {
let adjacent_edges = self.adjacent_edges(v);
// ...
}
}
struct UndirectedGraph { ... }
impl Graph for UndirectedGraph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput {
// ...
}
}
struct DirectedGraph { ... }
impl Graph for DirectedGraph {
fn adjacent_edges(&self, v: &Vertex) -> SomeOutput {
// ...
}
}