Struct的基本使用

使用struct關鍵字定義Struct類型。

具名Struct

具名Struct(named Struct)表示有字段名稱的Struct。Struct的字段(Field)也可以稱為Struct的屬性(Attribute)。

例如,定義一個名為Person的Struct結構體,Person包含三個屬性,分別是name、age和email,每個屬性都需要指定數據類型,這樣可以限制各屬性允許存放什麼類型的數據。


#![allow(unused)]
fn main() {
struct Person{
  name: String,
  age: u32,
  email: String, // 最後一個字段的逗號可省略,但建議保留
}
}

定義Struct後,可創建Struct的實例對象,為其各個屬性指定對應的值即可。

例如,構造Person結構體的實例對象user1,


#![allow(unused)]
fn main() {
let user1 = Person {
  name: String::from("junmajinlong"),
  email: String::from("[email protected]"),
  age: 23,
};
}

創建user1實例對象後,可以通過user1.name訪問它的name字段的值,user1.age訪問它的age字段的值。

以下是一段完整的代碼:

struct Person{
  name: String,
  age: u32,
  email: String,
}

fn main(){
  let user1 = Person{
    name: String::from("junmajinlong"),
    email: String::from("[email protected]"),
    age: 23,
  };
  // 訪問user1實例name字段、age字段和email字段的值
  println!(
    "name: {}, age: {}, email: {}",
    user1.name, user1.age, user1.email
  );
}

構造struct的簡寫方式

當要構造的Struct實例的字段值來自於變量,且這個變量名和字段名相同,則可以簡寫該字段。

struct Person{
  name: String,
  age: u32,
  email: String,
}

fn main(){
  let name = String::from("junmajinlong");
  let email = String::from("[email protected]");

  let user1 = Person{
    name,      // 簡寫,等價於name: name
    email,     // 簡寫,等價於email: email
    age: 23,
  };
}

有時候會基於一個Struct實例構造另一個Struct實例,Rust允許通過..xx的方式來簡化構造struct實例的寫法:


#![allow(unused)]
fn main() {
let name = String::from("junmajinlong");
let email = String::from("[email protected]");
let user1 = Person{
  name,
  email,
  age: 23,
};

let mut user2 = Person{
  name: String::from("gaoxiaofang"),
  email: String::from("[email protected]"),
  ..user1
};
}

上面的..user1表示讓user2借用或拷貝user1的某些字段值,由於user2中已經手動定義了name和email字段,因此..user1只借用了user1的age字段,即user2.age也是23。

注意,如果..base借用於base的字段是可Copy的,那麼在借用時會自動Copy,這樣在借用字段之後,base中的字段仍然有效。但如果借用的字段不是Copy的,那麼在借用時會將base中字段的所有權轉移走,使得base中的該字段無效。

例如,同時借用user1中的age字段和email字段,由於age是i32類型,是Copy的,所以user1.age仍然可用,但由於String類型不是Copy的,所以user1.email不可用。


#![allow(unused)]
fn main() {
let name = String::from("junmajinlong");
let email = String::from("[email protected]");
let user1 = Person{
  name,
  email,
  age: 23,
};

let mut user2 = Person{
  name: String::from("gaoxiaofang"),
  ..user1
};

// 報錯,user1.email字段值的所有權已借給user2
// println!("{}", user1.email);
// println!("{}", user1);       // 報錯
println!("{}", user1.name);     // 正確
println!("{}", user1.age);      // 正確
}

如果確實要借用user1的email屬性,可以使用..user1.clone()先拷貝堆內存中的user1,這樣就不會借用原始的user1中的email所有權。


#![allow(unused)]
fn main() {
let user2 = Person{
  name: String::from("ggg"),
  ..user1.clone()
}
}

tuple struct

除了named struct外,Rust還支持沒有字段名的struct結構體,稱為元組結構體(tuple struct)。

例如:


#![allow(unused)]
fn main() {
struct Color(i32, i32, i32); 
struct Point(i32, i32, i32); 

let black = Color(0, 0, 0); 
let origin = Point(0, 0, 0);
}

black和origin值的類型不同,因為它們是不同的結構體的實例。在其他方面,元組結構體實例類似於元組:可以將其解構,也可以使用.後跟索引來訪問單獨的值,等等。

unit-like struct

類單元結構體(unit-like struct)是沒有任何字段的空struct。


#![allow(unused)]
fn main() {
struct St;
}