代码之家  ›  专栏  ›  技术社区  ›  Tim

单元测试的条件可见性[副本]

  •  0
  • Tim  · 技术社区  · 7 年前

    我有一个功能可以作为 const :

    #![feature(const_fn)]
    
    // My crate would have:
    
    const fn very_complicated_logic(a: u8, b: u8) -> u8 {
        a * b
    }
    
    // The caller would have:
    
    const ANSWER: u8 = very_complicated_logic(1, 2);
    
    fn main() {}
    

    常量 static ,但应该能够在其他上下文中使用该函数:

    // My crate would have:
    
    fn very_complicated_logic(a: u8, b: u8) -> u8 {
        a * b
    }
    
    // The caller would have:    
    
    fn main() {
        let answer: u8 = very_complicated_logic(1, 2);
    }
    

    我如何有条件地编译我的代码,以便我的板条箱的冒险用户能够 const fn 支持,稳定的用户仍然可以使用我的代码,我不必每个函数都写两次?

    同样的问题也适用于函数的其他修饰符,但我不确定这些修饰符是否会根据某些条件发生变化:

    • default
    • unsafe
    • extern
    • pub (和其他可见性修改器)
    0 回复  |  直到 6 年前
        1
  •  10
  •   Shepmaster Tim Diekmann    6 年前

    宏来营救!

    #![cfg_attr(feature = "const-fn", feature(const_fn))]
    
    #[cfg(not(feature = "const-fn"))]
    macro_rules! maybe_const_fn {
        ($($tokens:tt)*) => {
            $($tokens)*
        };
    }
    
    #[cfg(feature = "const-fn")]
    macro_rules! maybe_const_fn {
        ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => {
            $(#[$($meta)*])* $vis const $ident $($tokens)*
        };
    }
    
    maybe_const_fn! {
        #[allow(unused)] // for demonstration purposes
        pub fn very_complicated_logic(a: u8, b: u8) -> u8 {
            internally_complicated_logic(a, b)
        }
    }
    
    maybe_const_fn! {
        fn internally_complicated_logic(a: u8, b: u8) -> u8 {
            a * b
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[cfg(feature = "const-fn")]
        #[test]
        fn use_in_const() {
            const ANSWER: u8 = very_complicated_logic(1, 2);
            drop(ANSWER);
        }
    
        #[test]
        fn use_in_variable() {
            let answer: u8 = very_complicated_logic(1, 2);
            drop(answer);
        }
    }
    

    连同这个一起 Cargo.toml

    [features]
    const-fn = []
    

    因为宏只能扩展到完整的语法片段(即宏不能简单地扩展到 const ),我们必须将整个函数包装在宏中,并使其某些部分未被解析,以便可以注入 在适当的地方。然后,解析器可以将整个内容解析为函数定义。

    常量 vis 匹配器( available since Rust 1.30.0