鍍金池/ 教程/ Java/ 屬性
標準輸入與輸出
消息傳遞
循環(huán)
注釋
Rust for Mac OS
幾種智能指針
Cell, RefCell
trait對象 (trait object)
rust web 開發(fā)
Unsafe、原始指針
Macro
迭代器
函數(shù)
Borrow, BorrowMut, ToOwned
快速上手
二叉樹
編輯器
測試與評測
Deref
安裝Rust
哈希表 HashMap
原生類型
17.錯誤處理
VS Code 安裝配置
動態(tài)數(shù)組Vec
模式匹配
操作符和格式化字符串
Rust for Linux
函數(shù)參數(shù)
Visual Studio
vim/GVim安裝配置
閉包作為參數(shù)和返回值
安全(Safety)
Cow
生命周期( Lifetime )
閉包的實現(xiàn)
所有權(Ownership)
Atom
將Rust編譯成庫
類型、運算符和字符串
類型系統(tǒng)中的幾個常見 trait
特性
屬性和編譯器參數(shù)
Spacemacs
集合類型
Rust json處理
Heap & Stack
并行
標準庫示例
基本程序結構
鏈表
trait 和 trait對象
前期準備
代碼風格
編譯器參數(shù)
基于語義化版本的項目版本聲明與管理
Rust 版本管理工具: rustup
引用&借用(References&Borrowing)
注釋與文檔
10.1 trait關鍵字
模式
調用ffi函數(shù)
unsafe
并發(fā),并行,多線程編程
AsRef 和 AsMut
Rust旅程
Rust for Windows
結構體與枚舉
條件分支
附錄I-術語表
變量綁定與原生類型
Mutex 與 RwLock
泛型
裸指針
常用數(shù)據(jù)結構實現(xiàn)
系統(tǒng)命令:調用grep
Into/From 及其在 String 和 &str 互轉上的應用
共享內存
Sublime
網絡模塊:W貓的回音
函數(shù)返回值
包和模塊
高階函數(shù)
函數(shù)與方法
match關鍵字
隊列
目錄操作:簡單grep
語句和表達式
并發(fā)編程
閉包
測試
閉包的語法
同步
迭代器
String
Send 和 Sync
Rc 和 Arc
屬性
Emacs
優(yōu)先隊列
Prelude
cargo簡介
控制流(control flow)
數(shù)組、動態(tài)數(shù)組和字符串
FFI
模塊和包系統(tǒng)、Prelude
實戰(zhàn)篇
Rust 是一門系統(tǒng)級編程語言,被設計為保證內存和線程安全,并防止段錯誤。作為系統(tǒng)級編程語言,它的基本理念是 “零開銷抽象”。理
運算符重載
Any和反射
rust數(shù)據(jù)庫操作
輸入輸出流
復合類型
性能測試

屬性

屬性

屬性(Attribute)是一種通用的用于表達元數(shù)據(jù)的特性,借鑒ECMA-334(C#)的語法來實現(xiàn)ECMA-335中描述的Attributes。屬性只能應用于Item(元素、項), 例如 use 聲明、模塊、函數(shù)等。

元素

在Rust中,Item是Crate(庫)的一個組成部分。它包括

  • extern crate聲明
  • use聲明
  • 模塊(模塊是一個Item的容器)
  • 函數(shù)
  • type定義
  • 結構體定義
  • 枚舉類型定義
  • 常量定義
  • 靜態(tài)變量定義
  • Trait定義
  • 實現(xiàn)(Impl)

這些Item是可以互相嵌套的,比如在一個函數(shù)中定義一個靜態(tài)變量、在一個模塊中使用use聲明或定義一個結構體。這些定義在某個作用域里面的Item跟你把 它寫到最外層作用域所實現(xiàn)的功能是一樣的,只不過你要訪問這些嵌套的Item就必須使用路徑(Path),如a::b::c。但一些外層的Item不允許你使用路徑去 訪問它的子Item,比如函數(shù),在函數(shù)中定義的靜態(tài)變量、結構體等,是不可以通過路徑來訪問的。

屬性的語法

屬性的語法借鑒于C#,看起來像是這樣子的

#[name(arg1, arg2 = "param")]

它是由一個#開啟,后面緊接著一個[],里面便是屬性的具體內容,它可以有如下幾種寫法:

  • 單個標識符代表的屬性名,如#[unix]
  • 單個標識符代表屬性名,后面緊跟著一個=,然后再跟著一個字面量(Literal),組成一個鍵值對,如#[link(name = "openssl")]
  • 單個標識符代表屬性名,后面跟著一個逗號隔開的子屬性的列表,如#[cfg(and(unix, not(windows)))]

#后面還可以緊跟一個!,比如#![feature(box_syntax)],這表示這個屬性是應用于它所在的這個Item。而如果沒有!則表示這個屬性僅應用于緊接著的那個Item。

例如:

// 為這個crate開啟box_syntax這個新特性
#![feature(box_syntax)]

// 這是一個單元測試函數(shù)
#[test]
fn test_foo() {
    /* ... */
}

// 條件編譯,只會在編譯目標為Linux時才會生效
#[cfg(target_os="linux")]
mod bar {
    /* ... */
}

// 為以下的這個type定義關掉non_camel_case_types的編譯警告
#[allow(non_camel_case_types)]
type int8_t = i8;

應用于Crate的屬性

  • crate_name - 指定Crate的名字。如#[crate_name = "my_crate"]則可以讓編譯出的庫名字為libmy_crate.rlib
  • crate_type - 指定Crate的類型,有以下幾種選擇

    • "bin" - 編譯為可執(zhí)行文件;
    • "lib" - 編譯為庫;
    • "dylib" - 編譯為動態(tài)鏈接庫;
    • "staticlib" - 編譯為靜態(tài)鏈接庫;
    • "rlib" - 編譯為Rust特有的庫文件,它是一種特殊的靜態(tài)鏈接庫格式,它里面會含有一些元數(shù)據(jù)供編譯器使用,最終會靜態(tài)鏈接到目標文件之中。

    #![crate_type = "dylib"]。

  • feature - 可以開啟一些不穩(wěn)定特性,只可在nightly版的編譯器中使用。
  • no_builtins - 去掉內建函數(shù)。
  • no_main- 不生成main這個符號,當你需要鏈接的庫中已經定義了main函數(shù)時會用到。
  • no_start - 不鏈接自帶的native庫。
  • no_std - 不鏈接自帶的std庫。
  • plugin - 加載編譯器插件,一般用于加載自定義的編譯器插件庫。用法是

    // 加載foo, bar兩個插件
    #![plugin(foo, bar)]
    // 或者給插件傳入必要的初始化參數(shù)
    #![plugin(foo(arg1, arg2))]
  • recursive_limit - 設置在編譯期最大的遞歸層級。比如自動解引用、遞歸定義的宏等。默認設置是#![recursive_limit = "64"]

應用于模塊的屬性

  • no_implicit_prelude - 取消自動插入use std::prelude::*。
  • path - 設置此mod的文件路徑。

    如聲明mod a;,則尋找

    • 本文件夾下的a.rs文件
    • 本文件夾下的a/mod.rs文件
    #[cfg(unix)]
    #[path = "sys/unix.rs"]
    mod sys;
    
    #[cfg(windows)]
    #[path = "sys/windows.rs"]
    mod sys;

應用于函數(shù)的屬性

  • main - 把這個函數(shù)作為入口函數(shù),替代fn main,會被入口函數(shù)(Entry Point)調用。
  • plugin_registrar - 編寫編譯器插件時用,用于定義編譯器插件的入口函數(shù)。
  • start - 把這個函數(shù)作為入口函數(shù)(Entry Point),改寫 start language item。
  • test - 指明這個函數(shù)為單元測試函數(shù),在非測試環(huán)境下不會被編譯。
  • should_panic - 指明這個單元測試函數(shù)必然會panic。
  • cold - 指明這個函數(shù)很可能是不會被執(zhí)行的,因此優(yōu)化的時候特別對待它。
// 把`my_main`作為主函數(shù)
#[main]
fn my_main() {

}

// 把`plugin_registrar`作為此編譯器插件的入口函數(shù)
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("rn", expand_rn);
}

// 把`entry_point`作為入口函數(shù),不再執(zhí)行標準庫中的初始化流程
#[start]
fn entry_point(argc: isize, argv: *const *const u8) -> isize {

}

// 定義一個單元測試
// 這個單元測試一定會panic
#[test]
#[should_panic]
fn my_test() {
    panic!("I expected to be panicked");
}

// 這個函數(shù)很可能是不會執(zhí)行的,
// 所以優(yōu)化的時候就換種方式
#[cold]
fn unlikely_to_be_executed() {

}

應用于全局靜態(tài)變量的屬性

  • thread_local - 只可用于static mut,表示這個變量是thread local的。

應用于FFI的屬性

extern塊可以應用以下屬性

  • link_args - 指定鏈接時給鏈接器的參數(shù),平臺和實現(xiàn)相關。
  • link - 說明這個塊需要鏈接一個native庫,它有以下參數(shù):

    • name - 庫的名字,比如libname.a的名字是name
    • kind - 庫的類型,它包括
      • dylib - 動態(tài)鏈接庫
      • static - 靜態(tài)庫
      • framework - OS X里的Framework
    #[link(name = "readline")]
    extern {
    
    }
    
    #[link(name = "CoreFoundation", kind = "framework")]
    extern {
    
    }

extern塊里面,可以使用

對于enum類型,可以使用

  • repr - 目前接受CC表示兼容C ABI。
#[repr(C)]
enum eType {
    Operator,
    Indicator,
}

對于struct類型,可以使用

  • repr - 目前只接受Cpacked,C表示結構體兼容C ABI,packed表示移除字段間的padding。

用于宏的屬性

  • macro_use - 把模塊或庫中定義的宏導出來

    • 應用于mod上,則把此模塊內定義的宏導出到它的父模塊中
    • 應用于extern crate上,則可以接受一個列表,如

        #[macro_use(debug, trace)]
        extern crate log;

      則可以只導入列表中指定的宏,若不指定則導入所有的宏。

  • macro_reexport - 應用于extern crate上,可以再把這些導入的宏再輸出出去給別的庫使用。

  • macro_export - 應于在宏上,可以使這個宏可以被導出給別的庫使用。

  • no_link - 應用于extern crate上,表示即使我們把它里面的庫導入進來了,但是不要把這個庫鏈接到目標文件中。

其它屬性

  • export_function - 用于靜態(tài)變量或函數(shù),指定它們在目標文件中的符號名。

  • link_section - 用于靜態(tài)變量或函數(shù),表示應該把它們放到哪個段中去。

  • no_mangle - 可以應用于任意的Item,表示取消對它們進行命名混淆,直接把它們的名字作為符號寫到目標文件中。

  • simd - 可以用于元組結構體上,并自動實現(xiàn)了數(shù)值運算符,這些操作會生成相應的SIMD指令。

  • doc - 為這個Item綁定文檔,跟///的功能一樣,用法是

    #[doc = "This is a doc"]
    struct Foo {}

條件編譯

有時候,我們想針對不同的編譯目標來生成不同的代碼,比如在編寫跨平臺模塊時,針對Linux和Windows分別使用不同的代碼邏輯。

條件編譯基本上就是使用cfg這個屬性,直接看例子

#[cfg(target_os = "macos")]
fn cross_platform() {
    // Will only be compiled on Mac OS, including Mac OS X
}

#[cfg(target_os = "windows")]
fn cross_platform() {
    // Will only be compiled on Windows
}

// 若條件`foo`或`bar`任意一個成立,則編譯以下的Item
#[cfg(any(foo, bar))]
fn need_foo_or_bar() {

}

// 針對32位的Unix系統(tǒng)
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {

}

// 若`foo`不成立時編譯
#[cfg(not(foo))]
fn needs_not_foo() {

}

其中,cfg可接受的條件有

  • debug_assertions - 若沒有開啟編譯優(yōu)化時就會成立。

  • target_arch = "..." - 目標平臺的CPU架構,包括但不限于x86, x86_64, mips, powerpc, armaarch64。

  • target_endian = "..." - 目標平臺的大小端,包括biglittle。

  • target_env = "..." - 表示使用的運行庫,比如musl表示使用的是MUSL的libc實現(xiàn), msvc表示使用微軟的MSVC,gnu表示使用GNU的實現(xiàn)。 但在部分平臺這個數(shù)據(jù)是空的。

  • target_family = "..." - 表示目標操作系統(tǒng)的類別,比如windowsunix。這個屬性可以直接作為條件使用,如#[unix],#[cfg(unix)]

  • target_os = "..." - 目標操作系統(tǒng),包括但不限于windows, macos, ios, linux, android, freebsd, dragonfly, bitrig, openbsd, netbsd。

  • target_pointer_width = "..." - 目標平臺的指針寬度,一般就是3264。

  • target_vendor = "..." - 生產商,例如apple, pc或大多數(shù)Linux系統(tǒng)的unknown。

  • test - 當啟動了單元測試時(即編譯時加了--test參數(shù),或使用cargo test)。

還可以根據(jù)一個條件去設置另一個條件,使用cfg_attr,如

#[cfg_attr(a, b)]

這表示若a成立,則這個就相當于#[cfg(b)]。

條件編譯屬性只可以應用于Item,如果想應用在非Item中怎么辦呢?可以使用cfg!宏,如

if cfg!(target_arch = "x86") {

} else if cfg!(target_arch = "x86_64") {

} else if cfg!(target_arch = "mips") {

} else {

}

這種方式不會產生任何運行時開銷,因為不成立的條件相當于里面的代碼根本不可能被執(zhí)行,編譯時會直接被優(yōu)化掉。

Linter參數(shù)

目前的Rust編譯器已自帶的Linter,它可以在編譯時靜態(tài)幫你檢測不用的代碼、死循環(huán)、編碼風格等等。Rust提供了一系列的屬性用于控制Linter的行為

  • allow(C) - 編譯器將不會警告對于C條件的檢查錯誤。
  • deny(C) - 編譯器遇到違反C條件的錯誤將直接當作編譯錯誤。
  • forbit(C) - 行為與deny(C)一樣,但這個將不允許別人使用allow(C)去修改。
  • warn(C) - 編譯器將對于C條件的檢查錯誤輸出警告。

編譯器支持的Lint檢查可以通過執(zhí)行rustc -W help來查看。

內聯(lián)參數(shù)

內聯(lián)函數(shù)即建議編譯器可以考慮把整個函數(shù)拷貝到調用者的函數(shù)體中,而不是生成一個call指令調用過去。這種優(yōu)化對于短函數(shù)非常有用,有利于提高性能。

編譯器自己會根據(jù)一些默認的條件來判斷一個函數(shù)是不是應該內聯(lián),若一個不應該被內聯(lián)的函數(shù)被內聯(lián)了,實際上會導致整個程序更慢。

可選的屬性有:

  • #[inline] - 建議編譯器內聯(lián)這個函數(shù)
  • #[inline(always)] - 要求編譯器必須內聯(lián)這個函數(shù)
  • #[inline(never)] - 要求編譯器不要內聯(lián)這個函數(shù)

內聯(lián)會導致在一個庫里面的代碼被插入到另一個庫中去。

自動實現(xiàn)Trait

編譯器提供一個編譯器插件叫作derive,它可以幫你去生成一些代碼去實現(xiàn)(impl)一些特定的Trait,如

#[derive(PartialEq, Clone)]
struct Foo<T> {
    a: i32,
    b: T,
}

編譯器會自動為你生成以下的代碼

impl<T: PartialEq> PartialEq for Foo<T> {
    fn eq(&self, other: &Foo<T>) -> bool {
        self.a == other.a && self.b == other.b
    }

    fn ne(&self, other: &Foo<T>) -> bool {
        self.a != other.a || self.b != other.b
    }
}

impl<T: Clone> Clone for Foo<T> {
    fn clone(&self) -> Foo<T> {
        Foo {
            a: self.a.clone(),
            b: self.b.clone(),
        }
    }
}

目前derive僅支持標準庫中部分的Trait。

編譯器特性

在非穩(wěn)定版的Rust編譯器中,可以使用一些不穩(wěn)定的功能,比如一些還在討論中的新功能、正在實現(xiàn)中的功能等。Rust編譯器提供一個應用于Crate的屬性feature來啟用這些不穩(wěn)定的功能,如

#![feature(advanced_slice_patterns, box_syntax, asm)]

具體可使用的編譯器特性會因編譯器版本的發(fā)布而不同,具體請閱讀官方文檔。

上一篇:Rust json處理下一篇:迭代器