zoukankan      html  css  js  c++  java
  • 【Rust-book】第五章 使用结构体来组织相关联的数据

    第五章 使用结构体来组织相关联的数据

    结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体。

    可以把结构体视作对象中的数据属性

    1 对比元组和结构体之间的异同,并演示如何使用结构体

    2 讨论如何定义方法和关联函数,他们可以指定那些与结构体数据相关的行为

    结构体和枚举体是用来创建类型的基本工具,在特定领域中的新类型同样可以享受到Rust编译时类型检查系统的所有优势。

    定义并实例化结构体

    结构体需要给每个数据赋予名字,可以清楚地表明它们地意义。

    由于字段命名,不再需要依赖顺序索引来指定或访问实例中的值。

    关键字struct被用来定义并命名结构体,一个良好的结构体名称应当能反映出自身数据组合的意义。在随后的花括号中声明所有数据的名字及类型,这些数据被称为字段。

    1 struct User {
    2   username: String,
    3    email: String, 
    4    sign_in_count: u64, 
    5    active: bool,
    6 }

    在为每个字段赋予具体的值来创建结构体实例,赋值的顺序不需要严格对应在结构体中声明它们的顺序。

    结构体的定义就像类型的通用模版一样,当我们将具体的数据填入模板时就创建出了新的实例。

    1 let user1 = User {
    2    email: String::from("someone@example.con"),
    3   username: String::from("someusername123"),
    4    active: true,
    5    sign_in_count: 1,
    6 };
    
    

    可以通过点号来访问实例中的特定字段。

    1 let mut user1 = User {
    2   email: String::from("someone@example.con"),
    3    username: String::from("someusername123"),
    4    active: true,
    5    sign_in_count: 1,
    6 };
    7 
    8 user1.email = String::from("anothermail@example.com");
    
    

    一旦实例可变,那么实例中的所有字段都将是可变的。

    Rust不允许我们将单独声明某一部分字段的可变性。

    1 fn build_user( email: String, username: String) -> User {
    2   User { // 在变量名与字段名相同时使用简化版的字段初始化方法
    3         // 参数与结构体字段拥有完全一致的名称,所以可以使用名为字段初始化简写的语法(field init shorthand)
    4      email,
    5       username,
    6       active: true,
    7       sign_in_count: 1,
    8    }
    9 }
    
    

    使用结构体更新语法根据其他实例创建新实例

    1 let user2 = User {
    2   email: String::from("another@example.com"),
    3    username: String::from("anotherusername455"),
    4    ..user1 // .. 表明剩下的那些还未被显示赋值字段都与给定实例拥有相同的值
    5 };
    
    

    使用不需要对字段命名的元组结构体来创建不同的类型

    元组结构体, 元组结构体同样拥有用于表明自身含义的名称,无须在声明它时对其字段进行命名,仅保留字段的类型即可。

    一般来说,当你想要给元组赋予名字,并使其区别与其他拥有同样定义的元组时,可以使用元祖结构体。

    1 struct Color(i32, i32, i32);
    2 struct Point(i32, i32, i32);
    3 
    4 let black = Color(0,0,0);
    5 let origin = Point(0,0,0);
    
    

    这里的 black ,origin 是不同的类型,因为它们两个分别是不同元组结构体的实例,

    所以定义的每一个结构体都拥有自己的类型,即便结构体中的字段拥有完全相同的类型。 例如,一个以Color类型作为参数的函数不能合法地接收Point类型的参数,即使它们都是由3个i32组成的。

    可以通过模式匹配解构为单独的部分,也可以通过.及索引来访问特定字段

    没有任何字段的空结构体

    单元结构体,没有任何字段的结构体()。也称为空结构体

    当需要在某些类型实现一个trait,却不需要在该类型中存储任何数据时,空结构体可以发挥作用。

     1 //对于引用来说有生命周期的限制
     2 struct User {
     3   username: &str, // expected lifetime parameter
     4    email: &str,
     5    sign_in_count: u64,
     6    active: bool,
     7 }
     8 
     9 fn main() {
    10   let user1 = User {
    11        email: "someone@example.com",
    12        username: "someusername123",
    13        active: true,
    14        aign_in_count: 1,
    15    };
    16 }
    
    

    一个结构体的示例程序

     1 fn main() {
     2   let width1 = 30;
     3   let height1 = 50;
     4     
     5    println!("The area of the rectangel is {} aquare pixels.", area(width1, height1));
     7 }
     8 fn area( u32, height: u32) -> u32 {
     9     width * height
    10 }

    元组重构

    1 fn main() {
    2   let rect1 = (30, 50);
    3     
    4    println!("The area of the rectangel is {} aquare pixels.", area(rect1));
    5 }
    6 
    7 fn area(dimensions: (u32, u32)) -> u32 {
    8     dimensions.0 * dimensions.1
    9 }

    使用结构体来重构代码,增加有意义的描述信息

     1 struct Rectangle {
     2      u32,
     3     height: u32,
     4 }
     5 
     6 fn main() {
     7     let rect1 = Rectangle {  30, height: 50 };
     8     println!("The area of the rectangel is {} aquare pixels.", area(&rect1));
     9 }
    10 
    11 fn area(rectange: &Rectangle) -> u32 { //不可变借用&Rectangle ,不会获得它的所有权
    12     rectangle.width * rectangle.height
    13 }

    通过派生trait增加适用功能

     1 #[derive(Debug)]
     2 struct Rectange {
     3      u32, 
     4     height: u32,
     5 }
     6 
     7 fn main() {
     8     let rect1 = Rectangle {  30, height: 50 };;
     9     println!("rect1 is {:?}", rect1);
    10 }

     

    方法

    方法总是被定义在某个结构体、枚举体或者triat对象,并且它们的第一个参数永远都是self,用于指代调用该方法的结构体实例。

     1 #[derive(Debug)]
     2 struct Rectangle {
     3      u32, 
     4     height: u32,
     5 }
     6 
     7 impl Rectangle {
     8     fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle 
     9         self.width * sellf.height
    10     }
    11 }
    12 
    13 fn main() {
    14     let rect1 = Rectangle {  30, height: 50 };
    15     println!("The area of the rectangel is {} aquare pixels.", rect1.area());
    16 }

    为了在Rectangle的上下文环境中定义这个函数,需要将area函数移动到impl 关键字起始的代码块中,并把签名中的第一个参数(也是唯一的那个参数)和函数中使用该参数的地方改为self.

    方法调用是通过实例后面加点好,并更上方法名、括号及可能的参数来实现。

    带有更多参数的方法

     1 fn main() {
     2     let rect1 = Rectangle {  30, height: 50 };
     3     let rect2 = Rectangle {  10, height: 40 };
     4     let rect3 = Rectangel {  60, height: 45 };
     5     
     6     println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
     7     println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
     8 }
     9 
    10 #[derive(Debug)]
    11 struct Rectangle {
    12      u32, 
    13     height: u32,
    14 }
    15 
    16 impl Rectangle {
    17     fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle 
    18         self.width * sellf.height
    19     }
    20     
    21     fn can_hold(&self, other: &Rectangle) -> bool {
    22         self.width > other.width && self.height > other.height
    23     }
    24 }
    25 
    26 // 关联函数
    27 impl Rectangle {
    28     fn squaer(size: u32) -> Rectange {
    29         Rectange {  size, height: size }
    30     }
    31 }
    关联函数常常用作构造器来返回一个结构体的新实例。

     类型名称后面添加::来调用关联函数

     

     :: 语法不仅被用于关联函数,还被用于模块创建的明命名空间。

     

    多个imple块

     
     1 impl Rectangle {
     2     fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle 
     3         self.width * sellf.height
     4     }
     5 }
     6 
     7 impl Rectangle {
     8     fn can_hold(&self, other: &Rectangle) -> bool {
     9         self.width > other.width && self.height > other.height
    10     }
    11 }
     
  • 相关阅读:
    php环境下所有的配置文件以及作用
    获取登陆用户的ip
    curl模拟post和get请求
    linux 下安装php curl扩展
    php常用面试知识点
    git使用步骤
    laravel框架基础知识点
    ci框架基础知识点
    ajax
    Mysql 中需不需要commit
  • 原文地址:https://www.cnblogs.com/Davirain/p/13458562.html
Copyright © 2011-2022 走看看