暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

写给 Web 开发者的 Rust 语言入门教程(23.条件编译)

最后的叶子的奇妙小屋 2021-09-24
1113

之前的文章:

0.引言

1.模块基础

2.变量

3.字符串

4.分支循环

5.数据表示

6.模块化

7.接口抽象

8.泛型

9.错误处理

10.内存布局

11.所有权

12.引用传递

13.引用字段

14.引用计数

15.泛化特化

16.闭包

17.普通宏

18.多线程

19.异步编程

20.工作区

21.测试

22.文档

本章主要介绍 rust 的条件编译,即根据编译目标和自定义条件进行选择性编译的机制。

feature

复杂的 crate (特别是 lib crate )往往包含一些“高级特性”,只有少部分情况下才会用到。此时可以用 feature 将它们标记出来,使这些高级特性在用不到的时候就不被编译,这样可以减少编译时间。

首先,在 lib crate 的 Cargo.toml 中可以指定有哪些 feature ,例如:

    [lib]
    crate-type = ['rlib']


    [features]
    add = [] # 一个名为 add 的 feature
    multiply = [] # 另一个名为 multiply 的 feature
    default = ["add"] # 默认启用名为 add 的 feature
    复制

    在代码中,可以指定哪些代码块在哪个 feature 下有效,例如:

      // 下面这个函数仅在 add feature 被启用时有效
      #[cfg(feature = "add")]
      pub fn add(a: u32, b: u32) -> u32 {
      a + b
      }


      // 下面这个函数仅在 multiply feature 被启用时有效
      #[cfg(feature = "multiply")]
      pub fn multiply(a: u32, b: u32) -> u32 {
      a * b
      }
      复制

      在引用这个 lib crate 时,可以指定有哪些 feature 需要启用,例如在引用它的 Cargo.toml 中:

        # 引入 my-feature-lib ,并启用 multiply feature
        [dependencies]
        my-feature-lib = { path = "../my-feature-lib", features = ["multiply"] }
        复制

        在代码中就可以使用:

          use my_feature_lib::{add, multiply};


          fn main() {
          // 因为 multiply feature 被启用了,所以 multiply 方法可用
              // (如果 Cargo.toml 中没有启用 multiply feature ,则会编译失败)
          println!("{}", multiply(2, 3)); // 输出 6
          // 因为 add feature 是默认启用的,所以 add 方法可用
          println!("{}", add(2, 3)); // 输出 5
          }
          复制

          可选依赖

          在实际场景中, feature 经常被用于控制需要编译的依赖项(因为编译很多依赖项真的很慢)。例如在 Cargo.toml 中这样写:

            [dependencies]
            rand = { version = "*", optional = true } # 可选依赖 rand


            [features]
            a-large-feature = ["rand"] # 启用这个 feature 时才会引入 rand
            default = [] # 默认不启用任何 feature
            复制

            这样,只要不用到 a-large-feature ,它包含的依赖项就不会被下载和编译,节约很多编译时间。

            系统环境条件编译

            除了 feature ,还可以根据编译目标系统环境来决定哪些代码被编译,哪些不被编译。例如:

              fn main() {
              // 如果编译成 windows 可执行程序
              #[cfg(target_os = "windows")]
              let os = "windows";
              // 如果编译成 linux 程序
              #[cfg(target_os = "linux")]
              let os = "linux";
              // 如果既不是 windows 也不是 linux 程序
              #[cfg(not(any(target_os = "windows", target_os = "linux")))]
              let os = "others";
              println!("This program is compiled for {}", os);
              }
              复制

              实际上 #[cfg(...)] 可以用于几乎任何形式的代码块。如果用在函数体内部,下面这种写法可能更好看:

                fn main() {
                let os = if cfg!(target_os = "windows") {
                "windows"
                } else if cfg!(target_os = "linux") {
                "linux"
                } else {
                "others"
                };
                println!("This program is compiled for {}", os);
                }
                复制

                在需要编译到不同系统环境时,这种根据不同系统环境来执行不同代码的情况很常见。这使得 #[cfg(...)] 还有不同用法,之后的文章必要时会介绍。

                文章转载自最后的叶子的奇妙小屋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论