【问题标题】:What does #[cfg(test)] do when placed at the top of lib.rs?#[cfg(test)] 放在 lib.rs 的顶部有什么作用?
【发布时间】:2019-10-31 23:19:58
【问题描述】:

我正在编写一个带有单元测试的 Rust 库(从 cargo 生成)。

我想在我的单元测试中使用 extern crate maplit 以便能够使用类似 JavaScript 的 hashmap 文字。我不想在我的库代码中使用 maplit。

maplit 提供了一个显然必须使用#[macro_use] 激活的宏。我能够让这一切正常工作的唯一方法是将其放在lib.rs 的顶部:

#[cfg(test)] #[macro_use] extern crate maplit;

// my crate-specific stuff

此时我意识到我不知道#[cfg(test)] 到底是做什么的。我在我的测试中使用它。根据约定,这些都包含在库代码中,如下所示:

// some library code

#[cfg(test)]
mod test {
  use super::*;
  // tests here
}

我原以为 #[cfg(test)] 行将直到文件(或块?)结尾之前的内容标记为仅适用于测试配置。

如果是这样,那么将这个指令放在lib.rs 的顶部似乎是个问题。当我编译一个发行版时,我的整个库不会被删除吗?

我试图查找有关 #[cfg(test)] 的确切作用的文档,但无济于事。

【问题讨论】:

  • 我确定,但我认为这意味着这段代码仅用于测试。但我认为可能还有更多,这种属性是编译器的一种神奇功能

标签: rust


【解决方案1】:
#[....]

上面是一个Rust Attribute,类似于其他语言的注解。例如;在 Java 中,我们有 @Annotation(....) 用于方法和类。与注解不同,rust 属性可以是遵循属性语法的表达式。

#[cfg(....)]

上面是compiler configuration 属性。 cfg() 是众多 built-in attributes 之一。

#[cfg(test)]

以上内容告诉 Rust 编译器,只有当 test 配置为 active 时,才应编译以下代码。您可以拥有其他配置属性,例如 debug、windows 或功能。

#[cfg(test)] #[macro_use] extern crate maplit;

是一样的

#[cfg(test)]
#[macro_use]
extern crate maplit;

这告诉 Rust 编译器仅在 test 配置处于活动状态时编译下一行,下一行告诉 Rust 仅使用来自以下 crate 的 macros。

如果是这样,那么将这个指令放在 lib.rs 的顶部似乎是个问题。当我编译一个发行版时,我的整个库不会被删除吗?

#[cfg(...)] 属性仅将编译器条件应用于它所附加的事物。

当您将属性放在文件顶部时,后跟一个空格。该属性附加到当前模块或板条箱。

如文档示例中所示,crate_type 应用于整个文件:

// General metadata applied to the enclosing module or crate.
#![crate_type = "lib"]

// A function marked as a unit test
#[test]
fn test_foo() {
    /* ... */
}

// A conditionally-compiled module
#[cfg(target_os = "linux")]
mod bar {
    /* ... */
}

// A lint attribute used to suppress a warning/error
#[allow(non_camel_case_types)]
type int8_t = i8;

// Inner attribute applies to the entire function.
fn some_unused_variables() {
  #![allow(unused_variables)]

  let x = ();
  let y = ();
  let z = ();
}

【讨论】:

  • 当然可以:play.rust-lang.org/… 在这个操场上,包括main 函数在内的整个文件仅用于测试,因此您可以测试此代码,但不能运行它,因为在非测试模式文件被视为空。
  • @Cerberus 你已经删除了主要功能。这不是整个文件的示例。如果您在 main 上方放置了一些东西,那么 main 将开始工作。对吗?
  • 它将停止编译 - play.rust-lang.org/… - 因为内部属性(如应用于整个文件的属性)不能出现在其他项目之后。
  • ...对不起,我误解了您的评论 - 这里是:play.rust-lang.org/… 它仍然被删除。
  • 这个答案与它链接的文档冲突,在所述文档中没有提到空格很重要,而是根据文档是否属性是“内部”(适用于它在里面的东西) 或 "outer"(应用于接下来的事情)取决于哈希后是否有感叹号。
猜你喜欢
  • 2019-09-23
  • 2023-04-11
  • 2016-04-14
  • 2011-08-25
  • 2010-11-03
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 2019-02-20
相关资源
最近更新 更多