概要

允許屬性在配對分支上

動機

有時希望使用屬性來注釋配對語句的分支,例如條件編譯 #[cfg] 或是分支權重(後者為最重要的用途)。

對於條件編譯,暫時得解決辦法是使用 #[cfg] 來重複宣告相同函式來處理不同的案例。一個案例研究是 sfackler 的 bindings to OpenSSL,在多數的發行版本中移除了 SSLv2 支持,因此 Rust bindings 部分需要被條件禁用。支援各種不同 SSL 版本最顯而易見的方法是使用枚舉。


#![allow(unused)]
fn main() {
pub enum SslMethod {
    #[cfg(sslv2)]
    /// Only support the SSLv2 protocol
    Sslv2,
    /// Only support the SSLv3 protocol
    Sslv3,
    /// Only support the TLSv1 protocol
    Tlsv1,
    /// Support the SSLv2, SSLv3 and TLSv1 protocols
    Sslv23,
}
}

然而,所有的 match 只能在 cfg 啟用時使用 Sslv2,例如下面內容是無效的:


#![allow(unused)]
fn main() {
fn name(method: SslMethod) -> &'static str {
    match method {
        Sslv2 => "SSLv2",
        Sslv3 => "SSLv3",
        _ => "..."
    }
}
}

一個有效的方法則必須有兩個定義:#[cfg(sslv2)] fn name(...)#[cfg(not(sslv2)] fn name(...) 。前者有 Sslv2 的分支,後者沒有。顯然,對於枚舉中每個額外的 cfg 變體,這都會以指數型的方式爆炸。

分支權重將允許仔細的微優化器(micro-optimiser)通知編譯器,例如,鮮少採取某個配對分支:


#![allow(unused)]
fn main() {
match foo {
    Common => {}
    #[cold]
    Rare => {}
}
}

詳細設計

一般的屬性語法,應用於整個配對分支。


#![allow(unused)]
fn main() {
match x {
    #[attr]
    Thing => {}

    #[attr]
    Foo | Bar => {}

    #[attr]
    _ => {}
}
}

替代方案

實際上沒有通用的替代方案; 人們也許可以用一些巨集(macro)和輔助函數來解決條件枚舉變體的配對問題; 但一般來說,這起不了任何作用。

未解決的問題