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 協議》,轉載必須註明作者和本文連結