學 Rust 要有大局觀 -五- 屬性的功能

什麼是 attribute?

attribute 是 rust 編譯器留給程序員的交互接口,一段代碼可以編譯產出爲二進制機器碼的過程通常來說,用戶的代碼是編譯器的輸入,當編譯器認爲代碼有問題,而程序員認爲沒問題的時候,必須允許程序員和編譯器有交互,允許程序員指導個別代碼的處理方式。

下面列舉幾個比較有代表性的場景:

讓編譯器閉嘴

rustc 要求結構體的命名需爲駱駝體,否則就會給出警告,假如程序員‘故意’要給出一個結構體,但是用了 python 的下劃線命名,爲了讓編譯器忽略對命名格式的‘異議’,可以通過

#[allow(non_camlel_case_types)]

這個標記,把它放在結構體聲明之前,編譯器就可以按照程序員的意願主動放過。而不是輸出一堆警告。

讓編譯器臨場應變

所謂的臨場應變經典場景主要是硬件和操作系統環境區別,比如當前這個程序員的操作系統是windows, CPU 架構是x86_64又或者是arm64, 代碼編譯的時候有些別人的代碼確實不可能編譯通過,程序員需要主動處理條件編譯規則,指導編譯器不同架構下同一個代碼應該編譯哪一個具體實現。對應的 attribute 類似#[cfg(windows)]的標記說明具體信息。

讓編譯器改變默認行爲

rust 瞭解之後你會知道有很多特有的術語,比如‘氧化’表示用 rust 去重寫一些現有的庫,或者用 rust 去實現一個特定的功能,但是畢竟很多東西編譯之後會有一些歷史命名習慣或者接口規則,不能按照 rust 本身的約定輸出,我們可以通過

#![crate_type = "cdylib"]
#![create_name=''crypto3]

這樣我們得到的名字是libcrypto3.so,我們還特意多加了一個3o後面,表示這個庫是我們自己用 rust 氧化之後的版本; 否則我們得到的是一個原版命名的libcrate.rlib這樣的 rust 二進制庫名字.

讓編譯器區別對待一些函數和代碼

單測就是這樣一個典型場景,相比於其他語言用文件名後綴,前綴,或者是引入某些包單獨編碼而言,rust 支持的更爲簡單直接,只要有 #[test]修飾的函數都會標記爲測試函數,會在cargo test命令下被拉出來單獨執行。

讓編譯自動添加一些行爲

這個用法就非常多樣了,典型場景是用#[derive(Debug)] 類似的標記好,以便編譯器自動給我們的類型添加特性.

#[derive(Debug)]
struct Point {
    x:f32,
    y:f32,
}

編譯器現在會給 Point 類自動添加一個fmt函數,這個函數功能類似 java 的toString, 或者 python 的__repr__等,注意:derive 的意義爲派生,但這裏並沒有一個默認的父類實現, 代碼都是編譯器根據當前的類程成員變量自動添加並編譯的。

derivetrait搭配使用共同左右,想要明白其中細節可以閱讀本系列上關於trait的單獨篇章.

結語

看了一些快速簡單的例子,你應該知道 attribute 這個概念是什麼內涵了,知道了內涵也就明白了概念,遇到的時候就不會有疑惑了。下一篇我們講一下 rust 惱人的宏,用不用不重要,重要的時候通過了解 rust,大家一起思考一下手頭使用的語言到底哪裏不好,爲什麼有新的設計。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Snof5jzcw9F7weHZwS5lYw