如何通过条件编译更改函数的限定符? [英] How do I change a function's qualifiers via conditional compilation?

查看:49
本文介绍了如何通过条件编译更改函数的限定符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可以作为 const 实现的函数:

I have a function that is capable of being implemented as a 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() {}

我想继续支持稳定的 Rust,因为它无法定义这样的函数.这些稳定的消费者将无法在 conststatic 中使用该函数,但应该能够在其他上下文中使用该函数:

I'd like to continue to support stable Rust where it's not possible to define such functions. These stable consumers would not be able to use the function in a const or static, but should be able to use the function in other contexts:

// 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);
}

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

How can I conditionally compile my code so that adventurous users of my crate could enable const fn support, stable users would still be able to use my code, and I don't have to write every function twice?

同样的问题应该适用于函数的其他修饰符,但我不确定这些修饰符会根据某些条件发生变化的具体情况:

The same question should apply to the other modifiers of a function, but I'm not sure of concrete cases where these modifiers would change based on some condition:

  • 默认
  • 不安全
  • extern
  • pub(和其他可见性修饰符)
  • default
  • unsafe
  • extern
  • pub (and other visibility modifiers)

推荐答案

宏来拯救!

#![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),我们必须将整个函数包装在宏中,并保留其中的某些部分未解析,以便我们可以在适当的地方注入 const.然后,解析器可以将整个事物解析为函数定义.

Since macros can only expand to complete pieces of syntax (i.e. a macro cannot simply expand to const), we have to wrap the whole function in the macro and leave some parts of it unparsed so that we can inject const in the appropriate place. Then, the parser can parse the whole thing as a function definition.

属性和可见性限定符需要特殊处理,因为它们必须出现在const 之前.我正在使用 vis 匹配器 (自 Rust 1.30.0 起可用) 以简化宏的实现.

Attributes and visibility qualifiers need special treatment, because they must appear before const. I am using the vis matcher (available since Rust 1.30.0) to simplify the macro's implementation.

这篇关于如何通过条件编译更改函数的限定符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆