`std`默認被鏈接到每個Rust包裝箱中。在一些情況下,這是不合適的,并且可以通過在包裝箱上加入`#![no_std]`屬性來避免這一點。
~~~
// a minimal library
#![crate_type="lib"]
#![feature(no_std)]
#![no_std]
~~~
很明顯不光庫可以使用這一點:你可以在可執行文件上使用`#[no_std]`,控制程序入口點有兩種可能的方式:`#[start]`屬性,或者用你自己的去替換C語言默認的`main`函數。
被標記為`#[start]`的函數傳遞的參數格式與C一致:
~~~
#![feature(lang_items, start, no_std)]
#![no_std]
// Pull in the system libc library for what crt0.o likely requires
extern crate libc;
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
~~~
要覆蓋編譯器插入的`main`函數,你必須使用`#![no_main]`并通過正確的ABI和正確的名字來創建合適的函數,這也需要需要覆蓋編譯器的命名改編:
~~~
#![feature(no_std)]
#![no_std]
#![no_main]
#![feature(lang_items, start)]
extern crate libc;
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
~~~
目前編譯器對能夠被可執行文件調用的符號做了一些假設。正常情況下,這些函數是由標準庫提供的,不過沒有它你就必須定義你自己的了。
這三個函數中的第一個`stack_exhausted`,當檢測到棧溢出時被調用。這個函數對于如何被調用和應該干什么有一些限制,不顧如果棧限制寄存器沒有被維護則一個線程可以有”無限的棧“,這種情況下這個函數不應該被觸發。
第二個函數,`eh_personality`,被編譯器的錯誤機制使用。它通常映射到GCC的特性函數上(查看[libstd實現](http://doc.rust-lang.org/std/rt/unwind/)來獲取更多信息),不過對于不會觸發恐慌的包裝箱可以確定這個函數不會被調用。最后一個函數,`panic_fmt`,也被編譯器的錯誤機制使用。
## 使用libcore
> **注意**:核心庫的結構是不穩定的,建議在任何可能的情況下使用標準庫。
通過上面的計數,我們構造了一個少見的運行Rust代碼的可執行程序。標準庫提供了很多功能,然而,這是Rust的生產力所需要的。如果標準庫是不足的話,那么可以使用被設計為標準庫替代的[libcore](http://doc.rust-lang.org/core/)。
核心庫只有很少的依賴并且比標準庫可移植性更強。另外,核心庫包含編寫符合習慣和高效Rust代碼的大部分功能。
例如,下面是一個計算由C提供的兩個向量的數量積的函數,使用常見的Rust實現。
~~~
#![feature(lang_items, start, no_std, core, libc)]
#![no_std]
extern crate core;
use core::prelude::*;
use core::mem;
#[no_mangle]
pub extern fn dot_product(a: *const u32, a_len: u32,
b: *const u32, b_len: u32) -> u32 {
use core::raw::Slice;
// Convert the provided arrays into Rust slices.
// The core::raw module guarantees that the Slice
// structure has the same memory layout as a &[T]
// slice.
//
// This is an unsafe operation because the compiler
// cannot tell the pointers are valid.
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
mem::transmute((
Slice { data: a, len: a_len as usize },
Slice { data: b, len: b_len as usize },
))
};
// Iterate over the slices, collecting the result
let mut ret = 0;
for (i, j) in a_slice.iter().zip(b_slice.iter()) {
ret += (*i) * (*j);
}
return ret;
}
#[lang = "panic_fmt"]
extern fn panic_fmt(args: &core::fmt::Arguments,
file: &str,
line: u32) -> ! {
loop {}
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
~~~
注意這里有一個額外的`lang`項與之前的例子不同,`panic_fmt`。它必須由libcore的調用者定義因為核心庫聲明了恐慌,但沒有定義它。`panic_fmt`項是這個包裝箱的恐慌定義,并且它必須確保不會返回。
正如你在例子中所看到的,核心庫嘗試在所有情況下提供Rust的功能,不管平臺的要求如何。另外一些庫,例如`liballoc`,為libcore增加了進行其它平臺相關假設的功能,不過這依舊比標準庫更有可移植性。
- 前言
- 1.介紹
- 2.準備
- 2.1.安裝Rust
- 2.2.Hello, world!
- 2.3.Hello, Cargo!
- 3.學習Rust
- 3.1.猜猜看
- 3.2.哲學家就餐問題
- 3.3.其它語言中的Rust
- 4.高效Rust
- 4.1.棧和堆
- 4.2.測試
- 4.3.條件編譯
- 4.4.文檔
- 4.5.迭代器
- 4.6.并發
- 4.7.錯誤處理
- 4.8.外部語言接口
- 4.9.Borrow 和 AsRef
- 4.10.發布途徑
- 5.語法和語義
- 5.1.變量綁定
- 5.2.函數
- 5.3.原生類型
- 5.4.注釋
- 5.5.If語句
- 5.6.for循環
- 5.7.while循環
- 5.8.所有權
- 5.9.引用和借用
- 5.10.生命周期
- 5.11.可變性
- 5.12.結構體
- 5.13.枚舉
- 5.14.匹配
- 5.15.模式
- 5.16.方法語法
- 5.17.Vectors
- 5.18.字符串
- 5.19.泛型
- 5.20.Traits
- 5.21.Drop
- 5.22.if let
- 5.23.trait對象
- 5.24.閉包
- 5.25.通用函數調用語法
- 5.26.包裝箱和模塊
- 5.27.`const`和`static`
- 5.28.屬性
- 5.29.`type`別名
- 5.30.類型轉換
- 5.31.關聯類型
- 5.32.不定長類型
- 5.33.運算符和重載
- 5.34.`Deref`強制多態
- 5.35.宏
- 5.36.裸指針
- 6.Rust開發版
- 6.1.編譯器插件
- 6.2.內聯匯編
- 6.3.不使用標準庫
- 6.4.固有功能
- 6.5.語言項
- 6.6.鏈接參數
- 6.7.基準測試
- 6.8.裝箱語法和模式
- 6.9.切片模式
- 6.10.關聯常量
- 7.詞匯表
- 8.學院派研究
- 勘誤