Rust 语言中的结构体

目录

1、结构体

2、结构体的定义和实例化

2.1 使用字段初始化简写语法

2.2 使用结构体更新语法从其他实例创建实例

2.3 没有命名字段的元组结构体

2.4 没有任何字段的类单元结构体

2.5 结构体示例程序

3、方法

3.1 关联函数

3.2 多个 impl 块


1、结构体

struct,或者 structure,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,struct 就像对象中的属性。

2、结构体的定义和实例化

结构体和我们之前论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。

定义结构体,需要使用 struct 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段field)。

我们看一下示例:

   struct people {
        name: String,
        age: u64,
    }

一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。

看一下示例:

   let user = People {
    name: String::from("zhou"),
    age: 23,
   };

为了从结构体中获取某个特定的值,可以使用点号。例如,我们获取一个用户对应的姓名和年龄,我们看下示例:

fn main() {
    struct People {
        name: String,
        age: u64,
    }
   let user = People {
    name: String::from("zhou"),
    age: 23,
   };
    println!("{} {} ", user.name, user.age)
} 

运行一下代码,看下是否可以获取对应的结果:

我们也可以通过方法传参,来返回一个初始化的实例:

fn user(name: String, age:u64) -> People {
    People {
        name: name,
        age: age
    }
}

2.1 使用字段初始化简写语法

参数名与字段名都完全相同,我们可以使用 字段初始化简写语法,示例如下所示:

fn user(name: String, age:u64) -> People {
    People {
        name,
        age
    }
}

2.2 使用结构体更新语法从其他实例创建实例

使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过 结构体更新语法struct update syntax)实现。

我们可以看下如下示例:

fn main() {
    struct People {
        name: String,
        age: u64,
    }

fn user(name: String, age:u64) -> People {
    People {
        name,
        age
    }
}
let u = user(String::from("wangwu"), 12);
println!("{} {} ", u.name, u.age);   // wangwu 12 
let u1 = user(u.name, 34);           // wangwu 34 
println!("{} {} ", u1.name, u1.age);
}

可以使用u1中的一个值来创建一个新的People示例,如下所示:

fn main() {
    struct People {
        name: String,
        age: u64,
    }

let u1 = People {
        name: String::from("zhou"),
        age: 12,
    };

println!("{} {} ", u1.name, u1.age);   // zhou 12
let u2 = People {name: String::from("wangwu"),..u1};  // wangwu 12
println!("{} {} ", u2.name, u2.age);
}

使用结构体更新语法,我们可以通过更少的代码来达到相同的效果,.. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。

通过以上代码,我们可以知道u2创建了一个新的实例,实例中的name字段与u1实例中的name不一样,而其余的值则是与u1中字段一样,..u1必须放在最后,用来指定剩下的字段值都从u1中获取,而结构体字段的顺序是可以任意的。

2.3 没有命名字段的元组结构体

也可以定义与元组类似的结构体,称为 元组结构体tuple structs)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的。

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

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

注意 black 和 origin 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。

2.4 没有任何字段的类单元结构体

我们也可以定义一个没有任何字段的结构体!它们被称为 类单元结构体unit-like structs)因为它们类似于 (),类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。

struct Color;
fn main() {
    let black = Color;
}

注意:之前定义结构体,我们使用了自身拥有所有权的 String 类型而不是 &str 字符串 slice 类型。这是一个有意而为之的选择,因为我们想要这个结构体拥有它所有的数据,为此只要整个结构体是有效的话其数据也是有效的。

可以使结构体存储被其他对象拥有的数据的引用,不过这么做的话需要用上 生命周期lifetimes

2.5 结构体示例程序

如果写一个计算长方形面积的方法,简单实现,可能会如下所示:

fn main() {
let w = 100;
let h = 200;
let result = area(w, h);
    println!("area is {:?}", result);
}

fn area (w: u64, h: u64) -> u64 {
    w * h
}

可以使用结构体,看起来更加语义化,如下所示:

struct AreaStruct {
    w: u64,
    h: u64
} 
fn main() {
    let a = AreaStruct {
        w: 100,
        h: 200
    };
let result = area(a);
    println!("area is {}", result);
}

fn area (a: AreaStruct) -> u64 {
    a.w * a.h
}

为了调试,我们可能会打印结构体里的属性,能,不过我们必须为结构体显式选择这个功能。为此,在结构体定义之前加上外部属性 #[derive(Debug)],如下所示:

#[derive(Debug)]
struct AreaStruct {
    w: u64,
    h: u64
} 
fn main() {
    let a = AreaStruct {
        w: 100,
        h: 200
    };
    println!("{:?}", a)
}

运行一下代码,看下打印结果,如下所示:

另一种使用 Debug 格式打印数值的方法是使用 dbg!宏。dbg! 宏接收一个表达式的所有权(与 println! 宏相反,后者接收的是引用),打印出代码中调用 dbg! 宏时所在的文件和行号,以及该表达式的结果值,并返回该值的所有权。

示例如下所示:

#[derive(Debug)]

struct AreaStruct {
    w: u64,
    h: u64
} 
fn main() {
    let a = AreaStruct {
        w: 100,
        h: 200
    };
    dbg!(a);
}

运行代码,看一下打印结果:

3、方法

方法(method)与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并且它们第一个参数总是 self,它代表调用该方法的结构体实例。

这是一个示例,如下所示:

#[derive(Debug)]
#[warn(dead_code)]

struct AreaStruct {
    w: u64,
    h: u64
} 
impl AreaStruct {
    fn area_me(&self) -> u64 {
        &self.w * &self.h
    }
    
}
fn main() {
    let a = AreaStruct {
        w: 100,
        h:100,
    };
    println!("value is {}", a.area_me())
}

在 C/C++ 语言中,有两个不同的运算符来调用方法:. 直接在对象上调用方法,而 -> 在一个对象的指针上调用方法,这时需要先解引用(dereference)指针。换句话说,如果 object 是一个指针,那么 object->something() 就像 (*object).something() 一样。

Rust 并没有一个与 -> 等效的运算符;相反,Rust 有一个叫 自动引用和解引用automatic referencing and dereferencing)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。

3.1 关联函数

所有在 impl 块中定义的函数被称为 关联函数associated functions),因为它们与 impl 后面命名的类型相关。我们可以定义不以 self 为第一参数的关联函数(因此不是方法),因为它们并不作用于一个结构体的实例。

不是方法的关联函数经常被用作返回一个结构体新实例的构造函数。这些函数的名称通常为 new ,但 new 并不是一个关键字。

示例如下所示:

struct AreaStruct {
    w: u64,
    h: u64
} 
impl AreaStruct {
    fn square(size: u64) -> Self {
        Self {
            w: size,
            h: size,
        }
    }
    
}

这样可以通过这个方法,返回一个新的实例。

3.2 多个 impl 块

结果体是允许有多个impl的实现的。我们可以写一个示例,如下所示:

#[derive(Debug)]
struct AreaStruct {
    w: u64,
    h: u64
} 
impl AreaStruct {
    fn area_me(&self) -> u64 {
        &self.w * &self.h
    }
}
impl AreaStruct {
    fn area_length(&self) -> u64 {
        &self.w * 2 +  &self.h * 2
    }
}
fn main() {
    let a = AreaStruct {
        w: 100,
        h:100,
    };
    println!("value is {}", a.area_length())
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/155671.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年09月 Python(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 以下选项中,不是tkinter变量类型的是?( ) A: IntVar() B: StringVar() C: DoubleVar() D: FloatVar() 答案:D tkinter 无 FloatVar()变量类型。 第2题 关于tkinter,以下说…

C++二分算法:使数组严格递增

涉及知识点 动态规划 二分查找 题目 给你两个整数数组 arr1 和 arr2,返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。 每一步「操作」中,你可以分别从 arr1 和 arr2 中各选出一个索引,分别为 i 和 j&#…

OceanBase:中国场景推动树立分布式数据库四项新标准

11月16日,在OceanBase2023年度发布会上,OceanBase CEO杨冰介绍,中国数字经济的蓬勃发展催生了对分布式数据库的强大需求,这种需求也牵引了OceanBase坚定投入自主研发,从而推动树立了分布式数据库的四项新标准。 据了解…

【计算机组成原理】定点加法、减法运算

系列文章目录 绘制出纯整数(1字节)和纯小数的数轴 将十进制数20.59375,转换成754标准的32位浮点数的二进制存储格式 用双符号位补码求 x 0.1010011, y -0.1001010, 分别求出 x y, x - y,并判溢出

单例模式(常用)

单例模式(单例设计模式) 在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。 单例模式的定义与特点 单例(Singleton)模式的定义:指…

Maven项目指定main方法配置

例如有个maven工程 打包后 xxx.jar 而这个maven工程里可能有很多main方法,比如测试的main方法 插件指定 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId>&…

KVM网络环境下vlan和trunk的理解

vmware exsi 平台&#xff0c;虚拟交换机管理界面的上行链路是什么意思 VMware ESXi中的虚拟交换机管理界面中的“上行链路”&#xff08;uplinks&#xff09;是指虚拟交换机连接到物理网络的物理网络适配器。在ESXi中&#xff0c;虚拟交换机&#xff08;vSwitch&#xff09;用…

【人工智能】本地运行开源项目MMSegmentation引发的问题

文章目录 ❌AssertionError: Torch not compiled with CUDA enabled问题描述问题分析解决方案总结参考文献 ❌AssertionError: Torch not compiled with CUDA enabled 问题描述 python demo/image_demo.py demo/demo.png configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-5…

rocketmq 安装dashboard1.0.0 mq消息控制台安装 rocketmq控制台安装 rocketmq-dashboard-1.0.0编译安装

1. 官网&#xff1a; 下载 | RocketMQ 2. dashboard安装包位置&#xff1a; 在连接最下面&#xff0c;点击download.zip即可 3. 需要安装maven, 编译命令&#xff1a; mvn clean install -U -Dmaven.test.skiptrue4. 启动jar: java -jar rocketmq-dashboard-1.0.0.jar &…

交换排序详讲:冒泡排序+快速排序(多方法+思路+图解+代码)

文章目录 交换排序一.冒泡排序二.快速排序1.挖坑法2.Hoare法 交换排序 根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 一.冒泡排序 /*** 冒泡排序* 时间复杂度 n^2* 空间复杂…

【开源】基于JAVA的大学兼职教师管理系统

项目编号&#xff1a; S 004 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S004&#xff0c;文末获取源码。} 项目编号&#xff1a;S004&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管…

《effective C++》条款10

令operator返回一个reference to *this int main() {int a, b, c 5;a b c;cout << a; } 这个代码&#xff0c;很明显输出的是5。所以我们在写这种连续赋值的时候&#xff0c;其对应的赋值运算符应当返回一个*this &#xff1a; class A { public:A(string ss, int x) …

vs2017打开工程提示若要解决此问题,请使用以下选择启动 Visual Studio 安装程序: 用于 x86 和 x64 的 Visual C++ MFC

下载 error MSB8036: 找不到 Windows SDK 版本8.1。请安装所需的版本的 Windows SDK 或者在项目属性页中或通过右键单击解决方案并选择“重定解决方案目标”来更改 SDK 版本。 error&#xff1a;D8016 “/ZI”和“/Gy-”命令行选项不兼容 ”问题解决

linux systemd start stop enable disable命令区别

一、systemd 的服务在三个文件件下 /lib/systemd/system /etc/systemd/system /usr/lib/systemd/system 终于明白这几个命令的区别 systemd star systemd stop systemd enable systemd disable 二、 1、用ssh服务为例&#xff0c;&#xff0c;ssh是客户端&#xff0c;远程ss…

delphi电子处方流转(医院)

【delphi电子处方流转(医院)】支持 就诊登记、电子处方上传预核验、处方处方医保电子签名、电子处方上传、电子处方撤销、电子处方信息查询、电子处方审核结果查询、电子处方取药结果查询、电子处方药品目录查询等功能。

短视频账号矩阵系统源码

短视频账号矩阵系统源码搭建步骤包括以下几个方面&#xff1a; 1. 确定账号类型和目标受众&#xff1a;确定要运营的短视频账号类型&#xff0c;如搞笑、美食、美妆等&#xff0c;并明确目标受众和定位。 2. 准备账号资料&#xff1a;准备相关资质和资料&#xff0c;如营业执照…

数据结构--栈与队列

目录 前言 1.栈 1.1栈的概念及结构 1.2接口函数 1.3函数实现 1.4如何使用 2.队列 2.1队列的概念及结构 2.2接口函数 2.3函数实现 2.4如何使用 前言 前面我们已经学习了顺序表和链表&#xff0c;今天我们来学习栈与队列&#xff0c;这两种结构也属于线性表&#xff0c;实…

解决windeployqt打包exe的“VCINSTALLDIR is not set“问题

今天在使用windeployqt部署qt的.exe文件时&#xff0c; 出现如下错误&#xff1a; windeployqt HelloQt.exe图(1) 报"VCINSTALLDIR路径"找不到 出现这种情况的原因是&#xff1a;VCINSTALLDIR环境没有配置&#xff0c;需要把Visual Studio的编译路径: ## 1) 社区版…

2018年五一杯数学建模A题徐州潘安湖风景区游览路线设计解题全过程文档及程序

2019年五一杯数学建模 A题 徐州潘安湖风景区游览路线设计 原题再现 徐州是一个老工业基地和资源型城市&#xff0c;煤炭开采历史长达130年。长期煤炭开采在徐州累计形成采煤塌陷区达数十万亩。位于徐州市贾汪区西南部、紧邻马庄的潘安湖湿地公园原来就是徐州最大的、塌陷最严…

关系代数、SQL语句和Go语言示例

近些年&#xff0c;数据库领域发展日新月异&#xff0c;除传统的关系型数据库外&#xff0c;还出现了许多新型的数据库&#xff0c;比如&#xff1a;以HBase、Cassandra、MongoDB为代表的NoSQL数据库&#xff0c;以InfluxDB、TDEngine为代表的时序数据[1]库&#xff0c;以Neo4J…