Laboratoria 11 XII¶
Celem zajęć jest zaznajomienie się z pisaniem makr w języku Rust.
Makra deklaratywne¶
Napisz makro do definiowania grafu korzystając z konstrukcji macro_rules!
.
Do reprezentacji grafów używać będziemy:
struct Graph {
name: &'static str,
nodes: Vec<Node>,
}
struct Node {
neighbors: Vec<usize>,
}
Przykładowe użycia makra:
// Poniższe wywołanie powinno zbudować graf reprezentujący nieskierowaną krawędź.
graph!(
Edge, // nazwa grafu
undirected, // krawędzie są nieskierowane
2, // ilość wierzchołków
(1, 2) // lista krawędzi
);
// Poniższe wywołanie powinno zbudować skierowany cykl na 4 wierzchołkach.
graph!(
Cycle,
directed,
4,
(1, 2), (2, 3), (3, 4), (4, 1)
);
Dla upewnienia, dopisz kilka testów jednostkowych. Dla przykładu:
assert_eq!(graph!(Empty, directed, 0), Graph { name: "Empty", nodes: vec![] });
Materiały:
Makra proceduralne¶
Dany jest trait:
trait MonoidElement: Add + AddAssign {
fn zero() -> Self;
}
Napisz makro proceduralne, które pozwoli automatycznie derywować MonoidElement
dla dowolnego typu, który jedno ze swoich pól ma oznaczone atrybutem #[monoid_element]
.
Dla przykładu, w sytuacji:
#[derive(MonoidElement)]
struct ComplexStruct {
a: (f32, f32),
b: [u8; 4],
#[monoid_element]
c: u32,
}
ComplexStruct
powinno implementować interfejs elementu monoidu tylko ze względu na pole c
.
Innymi słowy, zero
powinno zwrócić element neutralny (domyślny) dla u32
, a metody add
oraz add_assign
powinny modyfikować / brać pod uwagę wyłącznie pole c
.
Materiały