Open quinnwencn opened 1 month ago
在Rust語言中,宏是一個非常重要的部分。基於宏,我們可以編寫通用代碼、元編程、甚至是代碼生成。在Exercise的Space Age題目中,使用宏就可以生成各個星球的結構體定義和特定函數代碼的生產,從而簡化代碼下面,是我編寫的Space Age的解題代碼
// The code below is a stub. Just enough to satisfy the compiler.
// In order to pass the tests you can add-to or change any of this code.
#[derive(Debug)]
pub struct Duration (f64);
impl From<u64> for Duration {
fn from(s: u64) -> Self {
Duration (s as f64 / 31557600 as f64)
}
}
pub trait Planet {
fn period() -> f64 {
1.0
}
fn years_during(d: &Duration) -> f64 {
d.0 / Self::period()
}
}
macro_rules! impl_planet_for {
($name:ident, $period:expr) => {
pub struct $name;
impl Planet for $name {
fn period() -> f64 {
$period
}
}
}
}
impl_planet_for!(Mercury, 0.2408467);
impl_planet_for!(Venus, 0.61519726);
impl_planet_for!(Earth, 1.0);
impl_planet_for!(Mars, 1.8808158);
impl_planet_for!(Jupiter, 11.862615);
impl_planet_for!(Saturn, 29.447498);
impl_planet_for!(Uranus, 84.016846);
impl_planet_for!(Neptune, 164.79132);
可以看到,我在代碼中使用了宏來定義結構體和period
這個函數,代碼相對比較整潔。當然,這是我第二版代碼,第一版代碼沒有使用宏,這裏展示第一版的代碼,來說明宏的重要性:
/ The code below is a stub. Just enough to satisfy the compiler.
// In order to pass the tests you can add-to or change any of this code.
#[derive(Debug)]
pub struct Duration (u64);
impl From<u64> for Duration {
fn from(s: u64) -> Self {
Duration (s)
}
}
pub trait Planet {
fn years_during(d: &Duration) -> f64 {
d.0 as f64
}
}
pub struct Mercury;
pub struct Venus;
pub struct Earth;
pub struct Mars;
pub struct Jupiter;
pub struct Saturn;
pub struct Uranus;
pub struct Neptune;
impl Planet for Mercury {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 0.2408467 / 31557600.0
}
}
impl Planet for Venus {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 0.61519726 / 31557600.0
}
}
impl Planet for Earth {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 1.0 / 31557600.0
}
}
impl Planet for Mars {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 1.8808158 / 31557600.0
}
}
impl Planet for Jupiter {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 11.862615 / 31557600.0
}
}
impl Planet for Saturn {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 29.447498 / 31557600.0
}
}
impl Planet for Uranus {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 84.016846 / 31557600.0
}
}
impl Planet for Neptune {
fn years_during(d: &Duration) -> f64 {
d.0 as f64 / 164.79132 / 31557600.0
}
}
通過上述代碼的對比,我們可以看到宏對於代碼生成的重要性。這裏我根據我的學習介紹Rust中宏的定義和使用。在Rust中,宏的定義通常使用macro_rules! macro_name { ... }
代碼塊包含,其中的macro_name
就是宏的名稱。我們以題解中的宏為例:
macro_rules! impl_planet_for {
($name:ident, $period:expr) => {
pub struct $name;
impl Planet for $name {
fn period() -> f64 {
$period
}
}
}
}
impl_planet_for
是宏的名字,該宏定義了一個結構體和該結構體實現的一個trait。結構體的名稱由宏的第一個參數定義,第二個參數是trait的參數。這裏我們看到,name的類型是ident
,全稱叫identififiers,即標識符;第二個參數period的類型是expr
,即表達式,會產生一個值。宏的參數都以美元符號$開始。
除了ident
和expr
外,Rust中的標識符還有:
ty
: 類型,用於匹配類型,即變量的類型,全稱為type;pat
: 模式,用於匹配模式,即匹配變量綁定的模式,全稱為pattern;block
: 代碼塊,用於匹配代碼塊,即由一對花括號包圍的多個語句;item
: 匹配項,即Rust的頂級聲明,比如函數,結構體或者模塊等;path
: 路徑,用於匹配路徑,即標識符序列,表示變量、函數、模塊等的路徑;meta
: 元數據,用於匹配屬性中的元數據,即#[...]形式的註解
其他類型的宏,在遇到的時候再補充。
解決Space Age問題,並總結宏的定義和使用