rust-quiz:001-macro-count-statements.rs

godme發表於2022-07-07
macro_rules! m {
    ($($s:stmt)*) => {
        $(
            { stringify!($s); 1 }
        )<<*
    };
}

fn main() {
    print!(
        "{}{}{}",
        m! { return || true },
        m! { (return) || true },
        m! { {return} || true },
    );
}

statement

首先,要搞清楚語句宣告的的邊界是什麼。
多數情況下,當然是以;作為結尾,但是不應該忽略的還有一些特殊符號

  • ():優先求值
  • {}:特殊宣告邊界

return

這裡包含兩個意思,統一的概念叫做返回值

  • 使用return可以進行方法的中斷,直接進行值返回。
  • 沒有特殊宣告,{}域內最後一個表示式求值作為返回值
  • ;後返回的是()單元型別

||

雙重場景

  • 無參閉包
  • 真值or

<<

左移符號,n << 1相當於 n \times 2

! or never

一般用於匹配特殊分支,標識永不返回
特性之一是匹配任意型別。

*

macro_rules定義的宏裡面,多項展開中需要定一個展開式:$()
內部的*代表可省略,前提是是最後一個,否則多個展開之間還是會加上可省略符號。

展開

$(
            { stringify!($s); 1 }
)<<*

首先,傳入的多個語句,每一項展開的結果顯而易見,{ stringify!($s); 1 }
如果是多個語句,語句之間還會加上<<

最後列印是有返回值的,也就是說,我們還需要對{ stringify!($s); 1 }進行求值。
不難看出,實際的值就是最後的1
所以,我們最後的結果應該類似於1<<1<<1...
1的個數,對於傳入語句的個數n,換算之後返回的值應該是2 ^ {n-1}

因此,最後的結果就轉換為了判斷傳入的語句的個數。

判斷

  • return || true
    這裡應該拆分為return (|| true),不難看出,|| true是一個無參閉包。
    因此這裡返回的應該是1,整體就是一個語句。

  • (return) || true
    這裡,因為|| true丟失了return的作用,實際上變成了兩個bool||
    因為型別匹配,這裡(return)返回的是!,也就是never型別。
    整體就是一個or運算,因此語句數量還是1

  • {return} || true
    這裡需要想起的區分(){}的區別。

    • ():標識優先求值,但是不和整體的運算脫離
    • {}:自成一域,切斷與其他計算的關聯
      因此,這裡實際上是一個語句宣告{return},之後返回一個無參閉包|| true
      也就是說這裡有兩個語句,應該返回的是2

綜上所述,返回的結果應該是112

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章