# 結構體
> [structs.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/structs.md)
commit 6ba952020fbc91bad64be1ea0650bfba52e6aab4
結構體是一個創建更復雜數據類型的方法。例如,如果我們正在進行涉及到 2D 空間坐標的計算,我們將需要一個`x`和一個`y`值:
~~~
let origin_x = 0;
let origin_y = 0;
~~~
結構體讓我們組合它們倆為一個單獨,統一的數據類型:
~~~
struct Point {
x: i32,
y: i32,
}
fn main() {
let origin = Point { x: 0, y: 0 }; // origin: Point
println!("The origin is at ({}, {})", origin.x, origin.y);
}
~~~
這里有許多細節,讓我們分開說。我們使用了`struct`關鍵字后跟名字來定義了一個結構體。根據傳統,結構體使用大寫字母開頭并且使用駝峰命名法:`PointInSpace`而不要寫成`Point_In_Space`。
像往常一樣我們用`let`創建了一個結構體的實例,不過我們用`key: value`語法設置了每個字段。這里順序不必和聲明的時候一致。
最后,因為每個字段都有名字,我們可以訪問字段通過圓點記法:`origin.x`。
結構體中的值默認是不可變的,就像 Rust 中其它的綁定一樣。使用`mut`使其可變:
~~~
struct Point {
x: i32,
y: i32,
}
fn main() {
let mut point = Point { x: 0, y: 0 };
point.x = 5;
println!("The point is at ({}, {})", point.x, point.y);
}
~~~
上面的代碼會打印`The point is at (5, 0)`。
Rust 在語言級別不支持字段可變性,所以你不能像這么寫:
~~~
struct Point {
mut x: i32,
y: i32,
}
~~~
可變性是綁定的一個屬性,不是結構體自身的。如果你習慣于字段級別的可變性,這開始可能看起來有點奇怪,不過這樣明顯地簡化了問題。它甚至可以讓你使變量只可變一段臨時時間:
~~~
struct Point {
x: i32,
y: i32,
}
fn main() {
let mut point = Point { x: 0, y: 0 };
point.x = 5;
let point = point; // now immutable
point.y = 6; // this causes an error
}
~~~
你的結構體仍然可以包含`&mut`指針,它會給你一些類型的可變性:
~~~
struct Point {
x: i32,
y: i32,
}
struct PointRef<'a> {
x: &'a mut i32,
y: &'a mut i32,
}
fn main() {
let mut point = Point { x: 0, y: 0 };
{
let r = PointRef { x: &mut point.x, y: &mut point.y };
*r.x = 5;
*r.y = 6;
}
assert_eq!(5, point.x);
assert_eq!(6, point.y);
}
~~~
### 更新語法(Update syntax)
一個包含`..`的`struct`表明你想要使用一些其它結構體的拷貝的一些值。例如:
~~~
struct Point3d {
x: i32,
y: i32,
z: i32,
}
let mut point = Point3d { x: 0, y: 0, z: 0 };
point = Point3d { y: 1, .. point };
~~~
這給了`point`一個新的`y`,不過保留了`x`和`z`的值。這也并不必要是同樣的`struct`,你可以在創建新結構體時使用這個語法,并會拷貝你未指定的值:
~~~
# struct Point3d {
# x: i32,
# y: i32,
# z: i32,
# }
let origin = Point3d { x: 0, y: 0, z: 0 };
let point = Point3d { z: 1, x: 2, .. origin };
~~~
### 元組結構體
Rust有像另一個[元組](#)和結構體的混合體的數據類型。元組結構體有一個名字,不過它的字段沒有。他們用`struct`關鍵字聲明,并元組前面帶有一個名字:
~~~
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
~~~
這里`black`和`origin`并不相等,即使它們有一模一樣的值:
~~~
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
~~~
使用結構體幾乎總是好于使用元組結構體。我們可以這樣重寫`Color`和`Point`:
~~~
struct Color {
red: i32,
blue: i32,
green: i32,
}
struct Point {
x: i32,
y: i32,
z: i32,
}
~~~
現在,我們有了名字,而不是位置。好的名字是很重要的,使用結構體,我們就可以設置名字。
不過有種情況元組結構體非常有用,就是當元組結構體只有一個元素時。我們管它叫*新類型*(*newtype*),因為你創建了一個與元素相似的類型:
~~~
struct Inches(i32);
let length = Inches(10);
let Inches(integer_length) = length;
println!("length is {} inches", integer_length);
~~~
如你所見,你可以通過一個解構`let`來提取內部的整型,就像我們在講元組時說的那樣,`let Inches(integer_length)`給`integer_length`賦值為`10`。
### 類單元結構體(Unit-like structs)
你可以定義一個沒有任何成員的結構體:
~~~
struct Electron;
let x = Electron;
~~~
這樣的結構體叫做“類單元”因為它與一個空元組類似,`()`,這有時叫做“單元”。就像一個元組結構體,它定義了一個新類型。
就它本身來看沒什么用(雖然有時它可以作為一個標記類型),不過在與其它功能的結合中,它可以變得有用。例如,一個庫可能請求你創建一個實現了一個特定特性的結構來處理事件。如果你并不需要在結構中存儲任何數據,你可以僅僅創建一個類單元結構體。
- 前言
- 貢獻者
- 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.參考文獻
- 附錄:名詞中英文對照