結(jié)構(gòu)體是創(chuàng)建更復(fù)雜的數(shù)據(jù)類型的一種方式。例如,如果我們做涉及在二維空間中的坐標計算時,我們可能既需要 x 的值,也需要 y 的值:
let origin_x = 0;
let origin_y = 0;
一個結(jié)構(gòu)體讓我們將二者結(jié)合成為一個單一的,統(tǒng)一的數(shù)據(jù)類型:
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 關(guān)鍵字來聲明一個結(jié)構(gòu)體 ,同時 struct 后跟著此結(jié)構(gòu)體的名字。按照慣例,結(jié)構(gòu)體以大寫字母開頭,同時都為駝峰式書寫:PointInSpace ,而不是Point_In_Space。
我們可以通過 let 來創(chuàng)建一個我們的結(jié)構(gòu)體的實例,像往常一樣,但是我們使用一個關(guān)鍵字:值的語法風格來設(shè)置每個字段。不要求順序與原始聲明的順序相同。
最后,因為字段需要名稱,我們可以通過點符號來訪問字段:origin.x。
在默認情況下,結(jié)構(gòu)體中的值像 Rust 中的其他綁定一樣都是不可變的。我們使用 mut 關(guān)鍵字來使它們?yōu)榭勺儯?
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,
}
可變性是綁定的一個屬性,而不是結(jié)構(gòu)體本身。如果你習慣于字段級別可變性,第一次用起來會感覺很奇怪,但是它極大的簡化了一些東西。它甚至允許您使某東西為可變,但是僅僅適用于短時間內(nèi):
struct Point {
x: i32,
y: i32,
}
fn main() {
let mut point = Point { x: 0, y: 0 };
point.x = 5;
let point = point; // this new binding can’t change now
point.y = 6; // this causes an error
}
一個結(jié)構(gòu)體可以包含 .. 來表明你想要使用一些其他結(jié)構(gòu)體的副本用于某些值。例如:
struct Point3d {
x: i32,
y: i32,
z: i32,
}
let mut point = Point3d { x: 0, y: 0, z: 0 };
point = Point3d { y: 1, .. point };
以上代碼中給了 point 結(jié)構(gòu)體一個新的 y,但是仍然保持 x 和 z 的原來的值。它也并不一定是相同的結(jié)構(gòu)體,當你想要添加新的變量時可以使用這個語法,同時它會復(fù)制你沒有指定的值:
let origin = Point3d { x: 0, y: 0, z: 0 };
let point = Point3d { z: 1, x: 2, .. origin };
Rust 有另外一個數(shù)據(jù)類型就像一個數(shù)組與一個結(jié)構(gòu)體的混合,稱為“數(shù)組結(jié)構(gòu)體”。數(shù)組結(jié)構(gòu)體有一個名字,但是它們的字段沒有名字:
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
以上代碼中的兩個結(jié)構(gòu)體不相等,即使它們有相同的值:
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
與數(shù)組結(jié)構(gòu)體相比,使用結(jié)構(gòu)體幾乎總是比較好。我們可以像如下代碼一樣書寫 Color 和 Point:
struct Color {
red: i32,
blue: i32,
green: i32,
}
struct Point {
x: i32,
y: i32,
z: i32,
}
現(xiàn)在,我們有真正的名字,而不是位置。好名字固然重要,同時,結(jié)構(gòu)體我們需要有真正的名字。
在一種情況下,數(shù)組結(jié)構(gòu)體非常有用,盡管,那樣一個數(shù)組結(jié)構(gòu)體僅包含一個元素。我們稱之為‘新型’模式,因為它允許我們創(chuàng)建一個新的類型,不同于其包含的值,并表示它自己的語義:
struct Inches(i32);
let length = Inches(10);
let Inches(integer_length) = length;
println!("length is {} inches", integer_length);
正如你所看到的,你可以通過一個非結(jié)構(gòu)化的 let 關(guān)鍵字來提取內(nèi)在的整數(shù)類型,正如通常的數(shù)組一樣。在這種情況下,let Inches(integer_length) 將 10 賦值給 integer_length。
你可以定義一個根本沒有任何成員的結(jié)構(gòu)體:
struct Electron;
這樣的結(jié)構(gòu)體被稱為 ‘unit-like’ ,因為它類似于空數(shù)組,(),有時被稱為 ‘unit’。與數(shù)組結(jié)構(gòu)體一樣,它定義了一個新的類型。
這種結(jié)構(gòu)體通常對自己沒有什么用處(雖然它有時可以作為一個標記類型使用),但是結(jié)合其他的功能,它可以變的有用。例如,一個庫可能想要要求你創(chuàng)建一個可以實現(xiàn)某些特定特征的結(jié)構(gòu)體來處理事件。如果你沒有需要在結(jié)構(gòu)體中存儲的數(shù)據(jù),你可以只創(chuàng)建一個 unit-like 結(jié)構(gòu)體。
更多建議: