What are Rust's attributes?

Declarations can be annotated with attributes in Rust.

In essence, they attach some meta-data to a declaration which can be later used by the compiler to achieve some functionality.

To better understand this, consider the following example.

// Marking a function for testing.
#[test]
fn test_myFunction() {
    /* ... */
}

The #[test] attribute will mark the function test_myFunction for testing. So, when you normally compile and run this program, this function will not be built. Whereas, is you run the cargo test command, it will be executed.

Ways to add attributes

There are mainly 2 ways to add attributes.

  • Using #[<attribute_description>] -> Applies to the next item.
  • Using #![<attribute_description>] -> Applies to the item enclosing it.

For example,

#[attribute1]
struct myStruct;

mod myModule {
    #![attribute2]
}

Here, the attribute1 is applied to myStruct and the attribute2 is applied to myModule.

Examples of usage

An OS-specific module

#[cfg(target_os = "macos")]
mod macos_module {
}

This module would only compile on a Mac operating system.

Async functionality using custom runtimes

use tokio::io::{stdout, AsyncWriteExt as _};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
}

This would inform the Rust compiler to execute the main function using the Tokio runtime.