• 使用结构体组织相关联的数据(5)


    • struct 或者 structure ,是一个自定数据类型,允许你 包装命名 多个相关的值,从而形成一个有意义的组合

    5.使用结构体组织相关关联的数据

    1.结构体的定义和实例化

    • 定义结构体,需要使用struct关键词并为整个结构体提供一个名字
    • 结构体的名字需要描述它所组合的数据的意义
    • 大括号中,定义每一部分数据的名字和类型,称为字段
    1.1定义结构体
    struct User{
    	active: bool,
    	username: String,
    	email: String,
    	sign_in_count: u64,
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.2创建结构体的实例
    fn main(){
    	let mut userOne = 	User {
    		active: true,
    		username: String::from("张三"),
    		email: String::from("ghekswew@gmail.com"),
    		sign_in_count: 1,
    	};
    	println!("The userOne is email: {}",userOne.email);//ghekswew@gmail.com
    	// 结构体的实例是可变的,可以使用点号并为对应的字段赋值,以达到修改的目的
    	userOne.email = String::from("jkfhfh@gmail.com");
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 多个字段的修改
      • 前提是整个实例必须是可变的,Rust并不允许只将某个字段标记为可变
      fn build_user(email: String,username: String) -> User{
      	User{
      		active: true,
      		username: username,
      		email: email,
      		sign_in_count: 1,
      	}
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 返回一个带有给定的email和用户名的User实例
    1.3使用字段初始化简写语法
    • 参数名字段名都完全相同,使用字段初始化简写语法
    //重写build_user方法
    fn build_user(email: String,username: String)->User{
    	User{
    		active: true,
    		username,
    		email,
    		sign_in_count: 1,
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.3使用结构体更新语法从其他实例创建实例
    1.使用旧的实例创建新实例
    • 使用旧实例的大部分值但改变其部份值来创建一个新的结构体实例通常是很有用的
        let user2 = User {
            active: user1.active,
            username: user1.username,
            email: String::from("ghescjsjs@gmail.com"),
            sign_in_count: user1.sign_in_count,
        };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2. ..语法创建实例(旧实例为基础)
    • ..语法指定了剩余未显示设置值的字段应有与给定实例对应字段相同的值
    let user3 = User {
            email: String::from("hsxhsgwh@gmail.com"),
            // 这里不能使用user1,因为user1的username字段中的String被移动到user2,user1的username中的String失效`在这里插入代码片`
            
            ..user2
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.4使用没用命名字段的元组结构体来创建不同的类型
    • 可以定义与元组类似的结构体,称为元组构体
    • 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型
    struct Color(i32,i32,i32);
    struct Point(i32,i32,i32);
    fn main(){
    	let black = Color(0,0,0);
    	let origin = Point(0,0,0)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 元组结构体实例类似于元组,. +索引访问值等等
    1.5没有任何字段的类党员结构体
    • 定义一个没有任何字段的结构体,称为类单元结构体
    struct AlwaysEqual;
    fn main(){
    	let subject = AlwaysEqual;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.结构体示例程序

    fn main() {
        let width = 30;
        let height = 50;
        println!(
            "The area of the rectangle is {} square pixels.",
            area(width, height)
        );
    }
    fn area(width: u32, height: u32) -> u32 {
        width * height
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 函数area两个参数的关联性没表现出来
    2.1使用元组重构
    • 元组帮助增加了一些结构性,并且只需传入一个参数,但是还是不明确
    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
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2.2使用结构体重构: 赋予更多意义
    struct Rectangle {
        width: u32,
        height: u32,
    }
    
    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };
        println!(
            "The area of the rectangle is {} square pixels.",
            area(&rect1)
        );
    }
    fn area(rectangle: &Rectangle) -> u32 {
        rectangle.width * rectangle.height
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    2.3通过派生trait增加实用功能
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    
    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };
        //println!("rect1 is {:?}", rect1); // rect1 is Rectangle { width: 30, height: 50 }
    
        /*
        rect1 is Rectangle {
        width: 30,
        height: 50,
        }
         */
        //println!("rect1 is {:#?}", rect1);
    
        /*
        [src\main.rs:22] &rect1 = Rectangle {
        width: 30,
        height: 50,
        }
    
         */
        dbg!(&rect1);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • dbg! 宏接收一个表达式的所有权(与 println! 宏想法,后者接收的是引用)
    • 打印出代码中调用dbg!宏时所在文件和行号,以及该表达式的结果值,并返回该值的所有权

    3.方法语法

    • 方法函数区别
      • 都是使用fn关键字名称声明,可以拥有 参数返回值 ,同时包含在某处调用该方法时会执行的代码
      • 方法与函数不同的,它们在结构体的上线文中被定义(或者是枚举或trait对象的上下文),并且它们第一个参数总是self它代表调用该方法的结构体实例
    3.1定义方法
    #[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()
        );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 为了使函数定义于Rectangle的上下文中,使用impl块中的所有内容都将与Rectangle类型相关联
    • main中改为方法语法,使用实例调用 area 方法
    • 方法语法获取一个实例并加上一个点号,后跟方法名圆括号以及任何参数
    • area的签名中,使用&self来替代rectangle: &Rectangle,&self实际上是self: &self的缩写

    ==========================================================

    • 与字段同名的方法将被定义为只返回字段中的值,而不做其他事,这样的方法被称为getters
    • getters可以把字段变成私有的,当方法是公共的
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    impl Rectangle {
        fn area(&self) -> u32 {
            self.width * self.height
        }
        fn width(&self) -> bool {
            self.width > 0
        }
    }
    
    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };
        println!(
            "The area of the rectangle is {} square pixels.",
            rect1.area()
        );
        println!("The width is gt 0:{}", rect1.width()); //true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    3.2补充知识点(运算符到哪去了?)
    1.在C/C++中
    • 有两种不同的运算符来调用方法
      • . 直接在对象上调用方法
      • ->在一个对象的指针上调用方法,这时需要 先解引用
        • object -> something()(*object).something()一样
    2.在rust中
    • rust并没有一个与 ->等效的运算符,相反,Rust有自动引用解引用的功能
    • 以下两种等价
      • p1.distance(&p2)(&p1).distance(&p2)
    3.3带有更多参数的方法
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    impl Rectangle {
        fn area(&self) -> u32 {
            self.width * self.height
        }
        fn width(&self) -> bool {
            self.width > 0
        }
        fn can_hold(&self, other: &Rectangle) -> bool {
            self.width > other.width && self.height > other.height
        }
    }
    
    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)); //true
        println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // false
    
        println!(
            "The area of the rectangle is {} square pixels.",
            rect1.area()
        );
        println!("The width is gt 0:{}", rect1.width()); //true
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    3.4关联函数
    • 所有在impl块中定义的函数被称为关联函数
    • 可以定义不以self为第一参数的关联函数(不是方法),它们并不作用于一个结构体的实例
    • 使用结构体命名::语法来调用这个关联函数
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }
    impl Rectangle {
        fn square(size: u32) -> Self {
            Self {
                width: size,
                height: size,
            }
        }
    }
    fn main() {
        let sq = Rectangle::square(3);
        println!("{}", sq.width); //3
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    3.5多个impl块
    • 每个结构体都允许拥有多个impl
    impl Rectangle{
    	fn area(&self) -> u32{
    		self.width * self.height
    	}
    }
    impl Rectangle{
    	fn can_hold(&self,other: &Rectangle)-> bool{
    		self.width > other.width && self.height > other.height
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    汉字编码新尝试:字理组字编码方案v0.0
    [H5动画制作基础]随机四位数值
    机器人虚拟仿真工作站考试
    【Go-Lua】Golang嵌入Lua代码——gopher-lua
    Python学习:整数类型(int)详解
    机器学习之算法优化(一)
    [附源码]Python计算机毕业设计Django酒店客房管理信息系统
    Team Finance被黑分析|黑客自建Token“瞒天过海”,成功套取1450万美元
    挖掘PostgreSQL事务的“中间态”----更加严谨的数据一致性?
    【排版教程】使用Latex ACM 双栏会议模板如何添加跨栏的图片
  • 原文地址:https://blog.csdn.net/qq_39656068/article/details/132968457