Attributes

Attributes

Attributes are annotations you attach to your Rust code, like functions, structs, modules, or even entire crates. They provide extra information or instructions to the Rust compiler or other tools (like linters or documentation generators). They don't change the logic of the code directly, but they influence how it's compiled, checked, or processed.

Attributes can take arguments with different syntaxes:

#[attribute = "value"]
#[attribute(key = "value")]
#[attribute(value)]
#[attribute(value, value2)]

Inner attributes #![attr] apply to the item that the attribute is declared within. You often see these at the very top of a file (lib.rs or main.rs) to apply to the entire crate or module.

Lint Attributes

During early development, place the following attributes at the top of main.rs or lib.rs:

#![allow(unused_variables)]
#![allow(unused_mut)]
#![allow(unused_imports)]
#![allow(unused_must_use)]
// or simply: #![allow(unused)]
#![allow(dead_code)]
#![allow(missing_docs)]

// This import is not used anywhere.
use std::thread;

// This struct is public but is not documented:

pub struct S;

/// This function must be used.
#[must_use]
fn required() -> u32 {
    42
}

// Nothing calls this function.
fn dead_code() {}

fn main() {
    // This variable is not used.
    let x = 1;
    // This mutable variable is not used.
    let mut m = 2;
    // The return value of this function is not used.
    required();
    println!("Done!");
}

For production-ready code, replace the above by the following, for example.

//! This crate demonstrates the use of attributes for production code.
//! It includes examples of warnings, denials, and forbidden attributes.

// The `warn` attribute creates compiler warnings in case of violation.
#![warn(unused, missing_debug_implementations, missing_docs, rust_2018_idioms)]
// You may also add `missing_copy_implementations` if desirable.
// It detects potentially-forgotten implementations of `Copy` for public types.

// The `deny` attribute creates an error in case of violation.
#![deny(unreachable_pub)]
// The following prohibits unsafe blocks / functions.
// `forbid` is the same as `deny`, but also forbids changing the lint level
// afterwards.
#![forbid(unsafe_code)]

// Uncomment the following to observe compiler warnings or errors:

// WARNING: fn dead_code() { println!("This function is not used!"); }

// ERROR: unsafe fn unsafe_func() { println!("This function is marked as
// unsafe."); }

// ERROR
// fn contains_a_unsafe_block() {
//     unsafe {
//     }
// }

/// This is the required documentation for S.
/// We also had to derive `Debug` to avoid a warning.
#[derive(Debug)]
pub(crate) struct S;

/// Here is the required documentation
/// for the main function.
fn main() {
    let s = S;
    println!("{:?}", s);
}

You also apply these attributes to specific functions:

// Disables the `dead_code` lint
#![allow(dead_code)]

/// This function is defined but never called.
///
/// The `#[allow(dead_code)]` attribute disables the `dead_code` lint,
/// which would otherwise warn about this unused function.
fn unused_function() {}

fn main() {
    println!("Nobody is calling `unused_function`.");
}

List of lint checks: rustc -W help. rustc⮳ also recognizes the tool lints for "clippy" and "rustdoc" e.g. #![warn(clippy::pedantic)]

Automatically Derive Common Traits

See Automatic derivation.

Mark as must use

/// The `#[must_use]` attribute indicates that the results of a function must be
/// used. This attribute can also be applied to traits, structs, enums, etc.
#[must_use]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    println!("{}", add(1, 2));
}

Mark as deprecated

deprecated

#![allow(deprecated)]

// Mark a function as deprecated.
// That also works for structs, enums, etc...
#[deprecated(since = "5.2.0", note = "Use bar instead")]
pub fn foo() {
    println!("foo");
}

fn main() {
    // Use of a deprecated item.
    foo();
    // Normally, we would get a warning.
    // In this case, we used the module-wide #![allow(deprecated)] attribute
    // (first line above) to suppress it.
}

Compile Conditionally

Conditional compilation⮳.

/// This function only gets compiled if the target OS is Linux.
#[cfg(target_os = "linux")]
fn are_you_on_linux() {
    println!("You are running Linux!");
}

/// And this function only gets compiled if the target OS is *not*
/// Linux.
#[cfg(not(target_os = "linux"))]
fn are_you_on_linux() {
    println!("You are *not* running Linux!");
}

fn main() {
    are_you_on_linux();

    println!("Are you sure?");
    if cfg!(target_os = "linux") {
        // Alternative to `#[cfg(...)]`: use `cfg!(...)`.
        println!("Yes. It's definitely Linux!");
    } else {
        println!("Yes. It's definitely *not* Linux!");
    }
}

cfg-if

cfg-if cfg-if-crates.io cfg-if-github cfg-if-lib.rs

A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted.

use cfg_if::cfg_if;

/// This example demonstrates how to use `cfg-if` to conditionally compile
/// code blocks.
///
/// The `cfg-if` crate provides a convenient way to handle conditional
/// compilation based on configuration flags. This is particularly useful
/// when you need to write code that behaves differently depending on the
/// target platform, enabled features, or other build-time configurations.
// First, add the dependency to your Cargo.toml:
// [dependencies]
// cfg-if = "1.0.0"
fn main() {
    // Basic usage example:
    cfg_if! {
        if #[cfg(target_os = "windows")] {
            println!("Running on Windows!");
        } else if #[cfg(target_os = "macos")] {
            println!("Running on macOS!");
        } else if #[cfg(target_os = "linux")] {
            println!("Running on Linux!");
        } else {
            println!("Running on an unknown platform!");
        }
    }

    // Another example with feature flags:
    cfg_if! {
        if #[cfg(feature = "full")] {
            fn get_functionality() -> &'static str {
                "Full functionality enabled"
            }
        } else {
            fn get_functionality() -> &'static str {
                "Limited functionality only"
            }
        }
    }

    println!("Functionality: {}", get_functionality());

    // Nested example
    cfg_if! {
        if #[cfg(target_arch = "x86_64")] {
            cfg_if! {
                if #[cfg(target_feature = "avx2")] {
                    println!("Using AVX2 optimized routines");
                } else if #[cfg(target_feature = "sse2")] {
                    println!("Using SSE2 optimized routines");
                } else {
                    println!("Using standard routines");
                }
            }
        } else {
            println!("Architecture-specific optimizations not available");
        }
    }
}

Related Topics

  • Derive.
  • Rust Patterns.
  • Testing.

References