# 類型轉換
> [casting-between-types.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/casting-between-types.md)
commit 6ba952020fbc91bad64be1ea0650bfba52e6aab4
Rust,和它對安全的關注,提供了兩種不同的在不同類型間轉換的方式。第一個,`as`,用于安全轉換。相反,`transmute`允許任意的轉換,而這是 Rust 中最危險的功能之一!
### 強制轉換(Coercion)
類型間的強制轉換是隱式的并沒有自己的語法,不過可以寫作[`as`](#)。
強轉出現在`let`,`const`和`static`語句;函數調用參數;結構體初始化的字符值;和函數返回值中。
最常用的強轉的例子是從引用中去掉可變性:
- `&mut T`到`&T`
一個相似的轉換時去掉一個[裸指針](#)的可變性:
- `*mut T`到`*const T`
引用也能被強轉為裸指針:
- `&T`到`*const T`
- `&mut T`到`*mut T`
自定義強轉可以用[`Deref`](#)定義。
強轉是可傳遞的。
### `as`
`as`關鍵字進行安全的轉換:
~~~
let x: i32 = 5;
let y = x as i64;
~~~
有三種形式的安全轉換:顯式轉換,數字類型之間的轉換,和指針轉換。
轉換并不是可傳遞的:即便是`e as U1 as U2`是一個有效的表達式,`e as U2`也不必要是(事實上只有在`U1`強轉為`U2`時才有效)。
### 顯式轉換(Explicit coercions)
`e as U`是有效的僅當`e`是`T`類型而且`T`能強轉為`U`。
### 數值轉換
`e as U`的轉換在如下情況下也是有效的:
- `e`是`T`類型而且`T`和`U`是任意數值類型:`numeric-cast`
- `e`是一個類 C 語言枚舉(變量并沒有附加值),而且`U`是一個整型:`enum-cast`
- `e`是`bool`或`char`而且`T`是一個整型:`prim-int-cast`
- `e`是`u8`而且`U`是`char`:`u8-char-cast`
例如:
~~~
let one = true as u8;
let at_sign = 64 as char;
let two_hundred = -56i8 as u8;
~~~
數值轉換的語義是:
- 兩個相同大小的整型之間(例如:`i32`->`u32`)的轉換是一個`no-op`
- 從一個大的整型轉換為一個小的整型(例如:`u32`->`u8`)會截斷
- 從一個小的整型轉換為一個大的整型(例如:`u8`->`u32`)會
- 如果源類型是無符號的會補零(zero-extend)
- 如果源類型是有符號的會符號(sign-extend)
- 從一個浮點轉換為一個整型會向 0 舍入
- [注意:目前如果舍入的值并不能用目標整型表示的話會導致未定義行為(Undefined Behavior)](https://github.com/rust-lang/rust/issues/10184)。這包括 Inf 和 NaN。這是一個 bug 并會被修復。
- 從一個整型轉換為一個浮點會產生整型的浮點表示,如有必要會舍入(未指定舍入策略)
- 從 f32 轉換為 f64 是完美無缺的
- 從 f64 轉換為 f32 會產生最接近的可能值(未指定舍入策略)
- [注意:目前如果值是有限的不過大于或小于 f32 所能表示的最大最小值會導致未定義行為(Undefined Behavior)](https://github.com/rust-lang/rust/issues/10184)。這是一個 bug 并會被修復。
### 指針轉換
你也許會驚訝,[裸指針](#)與整型之間的轉換是安全的,而且不同類型的指針之間的轉換遵循一些限制。只有解引用指針是不安全的:
~~~
let a = 300 as *const char; // a pointer to location 300
let b = a as u32;
~~~
`e as U`在如下情況是一個有效的指針轉換:
- `e`是`*T`類型,`U`是`*U_0`類型,且要么`U_0: Sized`要么`unsize_kind(T) == unsize_kind(U_0)`:`ptr-ptr-cast`
- `e`是`*T`類型且`U`是數值類型,同時`T: Sized`:`ptr-addr-cast`
- `e`是一個整型且`U`是`*U_0`類型,同時`U_0: Sized`:`addr-ptr-cast`
- `e`是`&[T; n]`類型且`U`是`*const T`類型:`array-ptr-cast`
- `e`是函數指針且`U`是`*T`類型,同時`T: Sized`:`fptr-ptr-cast`
- `e`是函數指針且`U`是一個整型:`fptr-addr-cast`
### `transmute`
`as`只允許安全的轉換,并會拒絕例如嘗試將 4 個字節轉換為一個`u32`:
~~~
let a = [0u8, 0u8, 0u8, 0u8];
let b = a as u32; // four eights makes 32
~~~
這個錯誤為:
~~~
error: non-scalar cast: `[u8; 4]` as `u32`
let b = a as u32; // four eights makes 32
^~~~~~~~
~~~
這是一個“非標量轉換(non-scalar cast)”因為這里我們有多個值:四個元素的數組。這種類型的轉換是非常危險的,因為他們假設多種底層結構的實現方式。為此,我們需要一些更危險的東西。
`transmute`函數由[編譯器固有功能](#)提供,它做的工作非常簡單,不過非常可怕。它告訴Rust對待一個類型的值就像它是另一個類型一樣。它這樣做并不管類型檢查系統,并完全信任你。
在我們之前的例子中,我們知道一個有4個`u8`的數組可以正常代表一個`u32`,并且我們想要進行轉換。使用`transmute`而不是`as`,Rust允許我們:
~~~
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
}
~~~
為了使它編譯通過我們要把這些操作封裝到一個`unsafe`塊中。技術上講,只有`mem::transmute`調用自身需要位于塊中,不過在這個情況下包含所有相關的內容是有好處的,這樣你就知道該看哪了。在這例子中,`a`的細節也是重要的,所以它們放到了塊中。你會看到各種風格的代碼,有時上下文離得太遠,因此在`unsafe`中包含所有的代碼并不是一個好主意。
雖然`transmute`做了非常少的檢查,至少它確保了這些類型是相同大小的,這個錯誤:
~~~
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u64>(a);
}
~~~
和:
~~~
error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
(64 bits)
~~~
除了這些,你可以自行隨意轉換,只能幫你這么多了!
- 前言
- 貢獻者
- 1.介紹
- 2.準備
- 3.學習 Rust
- 3.1.猜猜看
- 3.2.哲學家就餐問題
- 3.3.其它語言中的 Rust
- 4.語法和語義
- 4.1.變量綁定
- 4.2.函數
- 4.3.原生類型
- 4.4.注釋
- 4.5.If語句
- 4.6.循環
- 4.7.所有權
- 4.8.引用和借用
- 4.9.生命周期
- 4.10.可變性
- 4.11.結構體
- 4.12.枚舉
- 4.13.匹配
- 4.14.模式
- 4.15.方法語法
- 4.16.Vectors
- 4.17.字符串
- 4.18.泛型
- 4.19.Traits
- 4.20.Drop
- 4.21.if let
- 4.22.trait 對象
- 4.23.閉包
- 4.24.通用函數調用語法
- 4.25.crate 和模塊
- 4.26.const和static
- 4.27.屬性
- 4.28.type別名
- 4.29.類型轉換
- 4.30.關聯類型
- 4.31.不定長類型
- 4.32.運算符和重載
- 4.33.Deref強制多態
- 4.34.宏
- 4.35.裸指針
- 4.36.不安全代碼
- 5.高效 Rust
- 5.1.棧和堆
- 5.2.測試
- 5.3.條件編譯
- 5.4.文檔
- 5.5.迭代器
- 5.6.并發
- 5.7.錯誤處理
- 5.8.選擇你的保證
- 5.9.外部函數接口
- 5.10.Borrow 和 AsRef
- 5.11.發布途徑
- 5.12.不使用標準庫
- 6.Rust 開發版
- 6.1.編譯器插件
- 6.2.內聯匯編
- 6.4.固有功能
- 6.5.語言項
- 6.6.鏈接進階
- 6.7.基準測試
- 6.8.裝箱語法和模式
- 6.9.切片模式
- 6.10.關聯常量
- 6.11.自定義內存分配器
- 7.詞匯表
- 8.語法索引
- 9.參考文獻
- 附錄:名詞中英文對照