Rust学习记录--C5 Rust struct

C5 Rust struct

定义和实例化struct

定义struct

  • 使用struct关键字,并为它命名

  • 格式:

    • 在花括号内,为所有字段(field)定义名称和类型
  • 例子:

    rust 复制代码
    struct User{
    		// 先写名称:再写类型
        username:String,
        email:String,
        sign_in_count:u64,
        // 最后一个在现有的rust版本中好像不加,也可以了
        active:bool,
    }

实例化struct

  • 实例化struct(使用struct)

    • 为每个字段指定具体的值
    • 无需按照声明的顺序进行指定
  • 例子

    rust 复制代码
    fn main(){
        let user1 = User{
        			// 每个字段都要指定具体的值
            username: String::from("Xiaoming"),
        			// 顺序可以不一致
            active: true,
            email: String::from("xiaoming@163.com"),
            sign_in_count:12,
        };
    }
    
    struct User{
        username:String,
        email:String,
        sign_in_count:u64,
        active:bool,
    }

取得struct里面的某个值

  • 使用点标记法

    rust 复制代码
    user1.email

注意

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

struct可以作为函数的返回值

  • 例子

    rust 复制代码
    fn build_user(email: String, username:String) ->User{
        return User{
            email:email,
            username:username,
            active:true,
            sign_in_count:01,
        };
    }

字段初始化简写

  • 当字段名与字段值对应变量名相同时,可以使用字段初始化简写

    rust 复制代码
    fn main(){
        let user2 = build_user(String::from("xiaohong@163.com"), String::from("xiaohong"));
        println!("email: {}, username: {}, active: {}, signInCount: {}", user2.email,user2.username, user2.active, user2.sign_in_count);
    }
    
    //函数传入参数名称和struct中定义的字段名称一样才可以简写
    fn build_user(email: String, username:String) ->User{
        return User{
            email,
            username,
            active:true,
            sign_in_count:01,
        };
    }
    
    struct User{
        email:String,
        username:String,
        sign_in_count:u64,
        active:bool,
    }

    错误示范:

struct更新语法

  • 基于已有的struct创建新的实例->使用struct更新语法

    rust 复制代码
    let user3 = User{
     username: String::from("Xiaoqiang"),
     email: String::from("Xiaoqiang@163.com"),
     sign_in_count: user1.sign_in_count,
     active: user1.active,
    };

    可以简写为

    rust 复制代码
    let user1 = User{
        username: String::from("Xiaoming"),
        active: true,
        email: String::from("xiaoming@163.com"),
        sign_in_count:12,
    };
    
    let user3 = User{
        username: String::from("Xiaoqiang"),
        email: String::from("Xiaoqiang@163.com"),
        // 表明剩下的两个字段直接使用user1的值
        ..user1
    };

Tuple struct

  • 定义类似tuple的struct,叫做tuple struct

    • tuple struct 整体有名字,但里面元素没有名字
    • 适用:相关整个tuple起名字,都是又不需要给各个元素起名字
  • 如何定义 tuple struct

    • struct tuple名称(元素类型, 元素类型, 元素类型);
    • 例子:
    rust 复制代码
    struct Color(i32,i32,i32);
    struct Point(i32,i32,i32);
    
    let black = Color(0,0,0);
    let origin_point = Point(0,0,0);
    • Color和Point都叫tuple struct,是不同的类型

Unit-Like Struct(没有任何字段)

  • 一个没有任何字段的struct
  • 适用于需要实现某个类型上的trait,但是里面没有想要存储的数据

struct数据的所有权

rust 复制代码
struct User{
    username:String,
    email:String,
    sign_in_count:u64,
    active:bool,
}
  • 字段使用了String而不是&str
    • 该struct拥有String字段的所有数据
    • 只有struct是有效的,里面的字段数据也是有效的
  • struct中可以存放引用,但是需要使用生命周期(以后会学)
    • 声明周期保证只有struct实例是有效的,里面的引用也是有效的
    • 如果struct直接存储引用,但是不用生命周期会报错

struct 例子

计算长方形面积的实现

  • 需求:计算长方形面积
  1. 初级:使用函数参数
rust 复制代码
fn main(){
    let w = 30;
    let l = 50;
    println!("Area: {}", area(w, l));
}

fn area(width:u32, length:u32)->u32
{
    return width*length;
}
复制代码
缺点:看起来w和l没有关联
  1. 使用tuple
rust 复制代码
fn main(){
    let w = 30;
    let l = 50;
    println!("Area: {}", area((w,l)));
}

// 使用tuple
fn area(dim:(u32,u32))->u32
{
    return dim.0*dim.1;
}
复制代码
缺点:长和宽虽然有关联了,但是没有名称了,可读性很差
  1. 使用struct + 函数实现
rust 复制代码
fn main(){
    let r1 = Rectangle{
        width:12,
        length:9,
    };
    let area = area(&r1);
    println!("Area: {}", area);
}
struct Rectangle{
    width:u32,
    length:u32,
}

fn area(rect: &Rectangle)->u32
{
    return rect.width*rect.length;
}
复制代码
优点: 长宽联系起来了且长宽有名字

输出一个struct

  • 想直接print r1这个struct

    • 结果会报错

    • 建议使用{:?} 或者 {:#?} ,但是加了之后还是会报错,报错是和debug有关

    • 添加#[derive(Debug)]{:?} 或者{:#?}

      • {:?}{:#?}的区别
        • {:?}是返回单行:
          Rectangle { width: 12, length: 9 }
        • {:#?}是返回有格式的,结构更清晰:
          Rectangle {
          width: 12,
          length: 9,
          }
  • 总结struct相关

    • std::fmt::Display
    • std::fmt::Debug
    • #[derive(Debug)]
    • {:?}
    • {:#?}

struct 方法

方法

  • 与函数的比较
    • 和函数类似:fn关键字/名称/参数/返回值
    • 和函数的不同点:
      • 方法是在struct(或者enum/trait对象)的上下文中定义
      • 方法的第一个参数是&self,表示方法被调用的struct实例
  • 上一个函数的缺点:单独的area函数很特殊,只适用于长方形,不适用于其他形状或者其他类型
    • ->将area函数和struct Rectangle关联到一起是最好的
    • 将原有的函数改成struct上定义的方法
  • 方法的定义和调用
    • 关键字impl
    • 方法的第一个参数是&self
    • 方法的调用:实例.函数名称() // 不需要显式的传入参数
    • 在调用方法时,rust根据情况自动添加&/&mut/*,以便于object可以匹配方法的签名
      • r1.area()(&r1).area() 等效
rust 复制代码
fn main(){
    let r1 = Rectangle{
        width:12,
        length:9,
    };
    // 方法的调用:实例.函数名称
    let area = r1.area();
    println!("Area: {}", area);
    println!("{:#?}", r1);
}

#[derive(Debug)]
struct Rectangle{
    width:u32,
    length:u32,
}

// struct的方法
impl Rectangle{
    fn area(&self)->u32
    {
        return self.width*self.length;
    }
}
复制代码
- 方法可以有多个参数,但是第一个必须是`&self`
rust 复制代码
impl Rectangle{
    fn area(&self)->u32
    {
        return self.width*self.length;
    }

	// 多个参数
    fn can_hold_another_rectangle(&self, other_rectangle: &Rectangle) -> bool
    {
        return self.width > other_rectangle.width && self.length > other_rectangle.length;
    }
}
复制代码
	![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7bba8c1e44054a368e5996249530d728.png)
- 上面这个叫关联函数,见下

关联函数

  • 关联函数:在impl块中定义不把self作为第一个参数的函数

    • (不是方法)
    • 不是在实例上调用的(我感觉像static)
    • 通常用于构造器->创建一个被关联类型的实例
    • 例子:String::from("xxx")
  • 关联函数的调用:类型名::函数名
    注意区别方法的调用和关联函数的调用的区别

    rust 复制代码
    #[derive(Debug)]
    struct Rectangle{
        width:u32,
        length:u32,
    }
    fn main(){
    	let r1 = Rectangle{
           width:12,
           length:9,
       };
       // 方法的调用:实例.函数名称
       let area = r1.area();
       println!("Area: {}", area);
       
    	//关联函数的调用
       let square = Rectangle::square(30);
    
       println!("{:#?}", square);
        
    }
    
    impl Rectangle{
    		// 方法
        fn area(&self)->u32
        {
            return self.width*self.length;
        }
        // 关联函数
        fn square(size: u32) -> Rectangle
        {
            return Rectangle { width: size, length: size };
        }
    }

多个impl块

  • 每个struct允许拥有多个impl块

2026/1/7

相关推荐
荒诞硬汉1 分钟前
面向对象(三)
java·开发语言
郝学胜-神的一滴3 分钟前
深入理解Linux中的Try锁机制
linux·服务器·开发语言·c++·程序人生
liliangcsdn3 分钟前
bash中awk如何切分输出
开发语言·bash
csbysj20209 分钟前
JSON.parse() 方法详解
开发语言
乐观主义现代人10 分钟前
redis 源码学习笔记
redis·笔记·学习
YJlio10 分钟前
Registry Usage (RU) 学习笔记(15.5):注册表内存占用体检与 Hive 体量分析
服务器·windows·笔记·python·学习·tcp/ip·django
奔波霸的伶俐虫12 分钟前
redisTemplate.opsForList()里面方法怎么用
java·开发语言·数据库·python·sql
yesyesido23 分钟前
智能文件格式转换器:文本/Excel与CSV无缝互转的在线工具
开发语言·python·excel
_200_25 分钟前
Lua 流程控制
开发语言·junit·lua
环黄金线HHJX.26 分钟前
拼音字母量子编程PQLAiQt架构”这一概念。结合上下文《QuantumTuan ⇆ QT:Qt》
开发语言·人工智能·qt·编辑器·量子计算