Rust(五)-struct

113 阅读3分钟

5.1定义并实例化struct

什么是struct

  • struct 结构体
    • 自定义的数据类型
    • 为相关联的值命名,打包=>有意义的组合
  • 定义struct
    • 使用struct关键字,并为整个struct命名
    • 在花括号内,为所有字段(field)定义名称和类型
    • 例如:
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
    }
    
  • 实例化struct
    • 想要使用struct,需要创建struct的实例:
      • 为每个字段指定具体值
      • 无需按声明的顺序进行指定
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
      }
    
      fn main() {
          let user1 = User {
              email: String::from("someone@example.com"),
              username: String::from("someusername123"),
              active: true,
              sign_in_count: 1,
          };
      }
    
    
  • 如何进行访问
    • 使用点标记法
    • 一旦struct的实例是可变的,那么实例中所有的字段都是可变的
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
      }
    
      fn main() {
          let mut user1 = User {
              email: String::from("someone@example.com"),
              username: String::from("someusername123"),
              active: true,
              sign_in_count: 1,
          };
    
          user1.email = String::from("anotheremail@example.com");
      }
    
    
  • struct作为函数的返回值
    • 函数的最后一个值作为返回值
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
      }
    
      fn build_user(email: String, username: String) -> User {
          User {
              email: email,
              username: username,
              active: true,
              sign_in_count: 1,
          }
      }
    
      fn main() {
          let user1 = build_user(
              String::from("someone@example.com"),
              String::from("someusername123"),
          );
      }
    
    
  • 字段初始化可简写
    • 当字段名与字段值对应变量名相同时,就可以使用字段初始化简写的方式:
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
      }
    
      fn build_user(email: String, username: String) -> User {
          User {
              email,
              username,
              active: true,
              sign_in_count: 1,
          }
      }
    
      fn main() {
          let user1 = build_user(
              String::from("someone@example.com"),
              String::from("someusername123"),
          );
      }
    
    
  • struct 更新语法
    • 当你想基于某个struct实例来创建一个新实例的时候,可以使用struct更新语法
    struct User {
      active: bool,
      username: String,
      email: String,
      sign_in_count: u64,
          }
    
          fn main() {
              // --snip--
    
              let user1 = User {
                  email: String::from("someone@example.com"),
                  username: String::from("someusername123"),
                  active: true,
                  sign_in_count: 1,
              };
    
              let user2 = User {
                  email: String::from("another@example.com"),
                  ..user1
              };
          }
    
  • tuple struct
    • 可以定义类似tuple的struct,叫作tuple struct
      • tuple struct 整体有个名,但里面的元素没有名
      • 适用:想给整个tuple起名,并让它不同于其它的tuple,而且又不需要给每个元素起名
      struct Color(i32, i32, i32);
      struct Point(i32, i32, i32);
      
      fn main() {
          let black = Color(0, 0, 0);
          let origin = Point(0, 0, 0);
      }
      
  • unit-like struct(没有任何字段)
    • 可以定义没有任何字段的struct, 叫做unit-like struct
    • 适用于需要在某个类型上实现某个trait,但是里面又没有想要存储的数据
  • struct 数据的所有权 +
    struct User {
      active: bool,
      username: &str,
      email: &str,
      sign_in_count: u64,
      }
    
      fn main() {
          let user1 = User {
              email: "someone@example.com",
              username: "someusername123",
              active: true,
              sign_in_count: 1,
          };
      }
    
    • 这里的字段使用了string 而不是 &str
      • 该struct实例拥有其所有的数据
      • 只要struct实例是有效的,那么里面的字段数据也是有效的
    • struct里也可以存放引用,但这需要使用生命周期
      • 生命周期保证只要struct实例是有效的, 那么里面的引用也是有效的
      • 如果struct里面存储引用,而不使用生命周期,就会报错

一个struct的例子

fn main() {
  let rect1 = (30, 50);

      println!(
          "The area of the rectangle is {} square pixels.",
          area(rect1)
      );
  }

  fn area(dimensions: (u32, u32)) -> u32 {
      dimensions.0 * dimensions.1
  }

struct 方法

  • 方法和函数类似:fn关键字、名称、参数、返回值
  • 方法与函数不同之处:
    • 方法是在struct的上下文中定义
    • 第一个参数是self,表示方法被调用的struct实例
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

  • 方法调用的运算符
    • C/C++: object->something()和(*object).something()一样
    • rust没有->运算符
    • rust会自动引用或解引用
  • 在调用方法时,Rust会根据情况自动添加 &、&mut或*,以便object可以匹配方法的签名。
  • 方法参数
    • 方法可以有多个参数
    fn main() {
      let rect1 = Rectangle {
          width: 30,
          height: 50,
      };
      let rect2 = Rectangle {
          width: 10,
          height: 40,
      };
      let rect3 = Rectangle {
          width: 60,
          height: 45,
      };
    
      println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
      println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
    }
    
    
  • 创建一个关联函数 +
    #[derive(Debug)]
          struct Rectangle {
              width: u32,
              height: u32,
          }
    
          impl Rectangle {
              fn square(size: u32) -> Rectangle {
                  Rectangle {
                      width: size,
                      height: size,
                  }
              }
          }
    
          fn main() {
              let sq = Rectangle::square(3);
          }
          Rectangle::square(3);