【Rust】——结构体struct

news2024/9/20 22:57:26

🎃个人专栏:

🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客

🐳Java基础:Java基础_IT闫的博客-CSDN博客

🐋c语言:c语言_IT闫的博客-CSDN博客

🐟MySQL:数据结构_IT闫的博客-CSDN博客

🐠数据结构:​​​​​​数据结构_IT闫的博客-CSDN博客

💎C++:C++_IT闫的博客-CSDN博客

🥽C51单片机:C51单片机(STC89C516)_IT闫的博客-CSDN博客

💻基于HTML5的网页设计及应用:基于HTML5的网页设计及应用_IT闫的博客-CSDN博客​​​​​​

🥏python:python_IT闫的博客-CSDN博客

🐠离散数学:离散数学_IT闫的博客-CSDN博客

​​​​​​🥽Linux:​​​​Linux_Y小夜的博客-CSDN博客

🚝Rust:Rust_Y小夜的博客-CSDN博客

欢迎收看,希望对大家有用!

目录

🎯定义并实例化struct

🥽什么是struct

🥽定义struct

🥽实例化struct

🎯struct例子

🎯struct

🥽struct方法

🥽方法调用的运算符

🥽方法参数

🥽关联函数

🥽多个impl块


🎯定义并实例化struct

🥽什么是struct

  • struct,结构体

-自定义的数据类型

-为相关联的值命名,打包=>有意的组合

🥽定义struct

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

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

        定义完每个字段的名称后,要用逗号分割,包括最后一个。

🥽实例化struct

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

fn main() {
    let user1 = User {
        active: true,
        username: String::from("someusername123"),
        email: String::from("someone@example.com"),
        sign_in_count: 1,
    };
}

为了从结构体中获取某个特定的值,可以使用点号。

  • 注意整个实例必须是可变的;
  • Rust 并不允许只将某个字段标记为可变。
  • 另外需要注意同其他任何表达式一样,我们可以在函数体的最后一个表达式中构造一个结构体的新实例,来隐式地返回这个实例。

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

fn build_user(email: String, username: String) -> User {
    User {
        active: true,
        username,
        email,
        sign_in_count: 1,
    }
}

更新语法:

fn main() {
    // --snip--

    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    };
}

Tuple struct:

        元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。

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 AlwaysEqual;

fn main() {
    let subject = AlwaysEqual;
}

        为了定义 AlwaysEqual,我们使用 struct 关键字,接着是我们想要的名称,然后是一个分号。不需要花括号或圆括号!

struct数据所有权:

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

🎯struct例子

需求:计算长方形面积

fn main() {
    let w=30;
    let l=50;
    println!("{}",area(w, l));
}

fn area(width:u32,length:u32) -> u32{
    width*length
}

        

        这个示例代码在调用 area 函数时传入每个维度,虽然可以正确计算出长方形的面积,但我们仍然可以修改这段代码来使它的意义更加明确,并且增加可读性。

使用元组重构:

fn main() {
    let rect=(30,50);
    println!("{}",area(rect));
}

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

        在某种程度上说,这个程序更好一点了。元组帮助我们增加了一些结构性,并且现在只需传一个参数。不过在另一方面,这个版本却有一点不明确了:元组并没有给出元素的名称,所以计算变得更费解了,因为不得不使用索引来获取元组的每一部分:

        在计算面积时将宽和高弄混倒无关紧要,不过当在屏幕上绘制长方形时就有问题了!我们必须牢记 width 的元组索引是 0height 的元组索引是 1。如果其他人要使用这些代码,他们必须要搞清楚这一点,并也要牢记于心。很容易忘记或者混淆这些值而造成错误,因为我们没有在代码中传达数据的意图。

用结构体重构:

  area 函数访问 Rectangle 实例的 width 和 height 字段(注意,访问对结构体的引用的字段不会移动字段的所有权,这就是为什么你经常看到对结构体的引用)。area 的函数签名现在明确的阐述了我们的意图:使用 Rectangle 的 width 和 height 字段,计算 Rectangle 的面积。这表明宽高是相互联系的,并为这些值提供了描述性的名称而不是使用元组的索引值 0 和 1 。结构体胜在更清晰明了。


像前面章节那样尝试使用 println!,但这并不行。

struct Rectangle {
    width: u32,
    height: u32,
}

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

    println!("rect1 is {}", rect1);
}

  {} 默认告诉 println! 使用被称为 Display 的格式:意在提供给直接终端用户查看的输出。目前为止见过的基本类型都默认实现了 Display,因为它就是向用户展示 1 或其他任何基本类型的唯一方式。不过对于结构体,println! 应该用来输出的格式是不明确的,因为这有更多显示的可能性:是否需要逗号?需要打印出大括号吗?所有字段都应该显示吗?由于这种不确定性,Rust 不会尝试猜测我们的意图,所以结构体并没有提供一个 Display 实现来使用 println! 与 {} 占位符。

        错误信息:

   = help: the trait `std::fmt::Display` is not implemented for `Rectangle`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

        现在 println! 宏调用看起来像 println!("rect1 is {:?}", rect1); 这样。在 {} 中加入 :? 指示符告诉 println! 我们想要使用叫做 Debug 的输出格式。Debug 是一个 trait,它允许我们以一种对开发者有帮助的方式打印结构体,以便当我们调试代码时能看到它的值。

这样调整后再次运行程序。见鬼了!仍然能看到一个错误:

error[E0277]: `Rectangle` doesn't implement `Debug`

        Rust 确实 包含了打印出调试信息的功能,不过我们必须为结构体显式选择这个功能。为此,在结构体定义之前加上外部属性 #[derive(Debug)];

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

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

    println!("rect1 is {:?}", rect1);
}

        好极了!这并不是最漂亮的输出,不过它显示这个实例的所有字段,毫无疑问这对调试有帮助。当我们有一个更大的结构体时,能有更易读一点的输出就好了,为此可以使用 {:#?} 替换 println! 字符串中的 {:?}。在这个例子中使用 {:#?} 

🎯struct

🥽struct方法

方法(method)与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。

方法与函数不同之处:

  • 因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文。
  • Rust 让你在第一个参数位置上只用 self 这个名字来缩写。
#[derive (Debug)]
struct  R{
    with:u32,
    length:u32,
}
impl R {
    fn area(&self) -> u32 {
    self.with*self.length
}
}
fn main() {
    let rect=R{
        with:30,
        length:50,
    };
    println!("{}",rect.area());
    println!("{:#?}",rect);
}

        使用方法替代函数,除了可使用方法语法和不需要在每个函数签名中重复 self 的类型之外,其主要好处在于组织性。我们将某个类型实例能做的所有事情都一起放入 impl 块中,而不是让将来的用户在我们的库中到处寻找 Rectangle 的功能。

🥽方法调用的运算符

        Rust 有一个叫 自动引用和解引用automatic referencing and dereferencing)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。

        它是这样工作的:当使用 object.something() 调用方法时,Rust 会自动为 object 添加 &&mut 或 * 以便使 object 与方法签名匹配。也就是说,这些代码是等价的:

p1.distance(&p2);
(&p1).distance(&p2);

🥽方法参数

#[derive (Debug)]
struct  R{
    with:u32,
    length:u32,
}
impl R {
    fn area(&self) -> u32 {
    self.with*self.length
}
    fn b(&self,other:&R)->bool{
        self.with>other.with&&self.length>other.length
    }
}
fn main() {
    let rect1=R{
        with:30,
        length:50,
    };
    let rect2=R{
        with:10,
        length:40,
    };
    let rect3=R{
        with:35,
        length:55,
    };
    println!("{}",rect1.b(&rect2));
    println!("{}",rect1.b(&rect3));
}

        因为我们只需要读取 rect2(而不是写入,这意味着我们需要一个不可变借用)

🥽关联函数

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

#[derive (Debug)]
struct  R{
    with:u32,
    length:u32,
}
impl R {
    fn area(&self) -> u32 {
    self.with*self.length
}
    fn b(&self,other:&R)->bool{
        self.with>other.with&&self.length>other.length
    }
    fn sq(size:u32) ->R{
        R{
            with:size,
            length:size,
        }
    }
}
fn main() {
    let s=R::sq(20);
    let rect1=R{
        with:30,
        length:50,
    };
    let rect2=R{
        with:10,
        length:40,
    };
    let rect3=R{
        with:35,
        length:55,
    };
    println!("{}",rect1.b(&rect2));
    println!("{}",rect1.b(&rect3));
}
  • 使用结构体名和 :: 语法来调用这个关联函数
  • 这个函数位于结构体的命名空间中::: 语法用于关联函数和模块创建的命名空间。

🥽多个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
    }
}

意义不大,但不存在错误。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue系列——vscode,node.js vue开发环境搭建

第一步安装node.js 推荐使用nvm进行node.js 的安装 nvm(Node.js version manager) 是一个命令行应用,可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 可以去网上查找相关版本 我这里使用 nvm-setu… 链接:https://pan.baidu.com/s/1UEUtmzw5x…

spring事务方法调用不生效的场景

同一个类中&#xff0c;事务方法调用非事务方法时&#xff0c;事务是可以生效的。反例事务不生效见以下 4. 同一个类中&#xff0c;方法内部调用 Autowired private XXXMapper xxxMapper; Autowired private YYYMapper yyyMapper; Transactional public ResultVO<AssetCh…

pag动效预览

潮玩apk里面分析静态资源发现动效有lottie 和pag文件 PAG官网 | PAG动效PAG动效组件可以降低或消除动效相关的研发成本&#xff0c;接入SDK后&#xff0c;设计师可通过PAGExpoter、PAGViewer等工具&#xff0c;一键将设计师在 AE 中制作的动效内容导出成素材文件&#xff0c;并…

【QT 5 +Linux下软件qt软件打包+qt生成软件创建可以安装压缩包+学习他人文章+第三篇:学习打包】

【QT 5 Linux下软件qt软件打包qt生成软件创建可以安装压缩包学习他人文章第三篇&#xff1a;学习打包】 1、前言2、实验环境3、自我学习总结-本篇总结&#xff08;1&#xff09;了解安装包的目录结构&#xff08;2&#xff09;了解要编写文件与编写脚本1. control文件2. postin…

vue3+vite 项目的创建

这里要提醒一下&#xff0c;如果我们要使用 vue3 的组合式api 的写法的话&#xff0c; 那么我们使用的 vue 版本不能低于 vue3.2 版本&#xff0c;不能低于 vue3.2 版本&#xff0c;不能低于 vue3.2 版本 vue2 已停止维护了&#xff0c; 现在全面拥抱vue3 之前用 vue-cli 创建…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:图片边框设置)

设置容器组件的图片边框样式。 说明&#xff1a; 从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 borderImage borderImage(value: BorderImageOption) 设置组件的图片边框。 卡片能力&#xff1a; 从API version 9开始…

2.2_4 调度算法的评价指标

文章目录 2.2_4 调度算法的评价指标&#xff08;一&#xff09;CPU利用率&#xff08;二&#xff09;系统吞吐量&#xff08;三&#xff09;周转时间&#xff08;四&#xff09;等待时间&#xff08;五&#xff09;响应时间 总结 2.2_4 调度算法的评价指标 注&#xff1a;要理解…

CentOs的yum报错: except KeyboardInterrupt, e:

1.报错 File “/bin/yum”, line 30 except KeyboardInterrupt, e: ^^^^^^^^^^^^^^^^^^^^ 2.原因&#xff1a;yum需要用python2编译&#xff0c;如果服务器安装的是python3.6并作为默认编译器的话&#xff0c;就会出现这个错误。 3.解决方法&#xff1a;whereis python 4.修改y…

【EI会议征稿通知】第三届新能源、储能与电力工程国际学术会议(NESP 2024)

第三届新能源、储能与电力工程国际学术会议&#xff08;NESP 2024&#xff09; 2024 3rd International Conference on New Energy, Energy Storage and Power Engineering (NESP 2024) 近几十年来&#xff0c;全球能源消耗迅速增加&#xff0c;因此寻找和开发性能优良的环保…

如何根据我的世界/Minecraft玩家数量选择合适的服务器配置,包括内存和CPU核心数的实际案例分析?

根据Minecraft玩家数量选择合适的服务器配置&#xff0c;首先需要考虑的是服务器的处理能力&#xff0c;这主要由CPU和内存决定。对于Minecraft服务器来说&#xff0c;CPU核心数直接影响到服务器能够同时处理的任务数量&#xff0c;而内存容量则决定了服务器能承载的人数。 对…

P1160 队列安排题解

题目 一个学校里老师要将班上N个同学排成一列&#xff0c;同学被编号为1∼N&#xff0c;他采取如下的方法&#xff1a; 先将1号同学安排进队列&#xff0c;这时队列中只有他一个人&#xff1b; 2∼N号同学依次入列&#xff0c;编号为i的同学入列方式为&#xff1a;老师指定编…

我写了个ImageWindow应用

文章目录 0 引言1 应用简介2 主要功能和特点2.1 多图像同/异步像素级对比2.2 支持多达30种图像格式2.3 高效率的图像处理性能 3 简明使用教程3.1 软件下载安装与更新3.1.1 软件下载与安装3.1.2 软件更新 3.2 多视窗添加并自动最优排列3.3 多样化图像导入方式3.4 自动切换显示模…

如何实现WordPress后台显示文章、分类目录、标签等的ID?

我们平时在使用WordPress的过程中&#xff0c;偶尔需要用到文章的ID&#xff0c;或分类目录ID&#xff0c;或标签ID&#xff0c;或媒体库ID&#xff0c;或评论ID&#xff0c;或用户ID等&#xff0c;但是WordPress后台默认是不显示它们的ID的。 今天boke112百科就跟大家分享如何…

Linux 下安装Jupyter

pip3 install jupyter pip3 install ipython -------------------------------------------- pip3 install jupyterlab jupyter lab pip3 list | grep jupyterlab 启动&#xff1a; python3 -m jupyter lab 2.安装朱皮特 pip3 install -i https://pypi.douban.com/simpl…

力扣1107 每日新用户统计

力扣SQL查询案例——在过去90天内&#xff0c;每个日期首次登录的用户数 目录 题目描述 解题思路 完整代码 题目描述 Traffic 表&#xff1a; ------------------------ | Column Name | Type | ------------------------ | user_id | int | | activity …

计算机二级MySQL-错题、知识点合集04

计算机二级MySQL 第四章 索引 主键约束&#xff0c;不允许为空也不允许重复。 NOT NULL非空约束属于自定义完整约束 PRIMARY KEY 属于实体完整性约束 FOREIGN KEY外键约束 外键与其引用的主键应分别属于不同的表&#xff0c;可以属于同一个关系&#xff1b;一个关系中可以定…

如何在Window系统部署BUG管理软件并结合内网穿透实现远程管理本地BUG

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

css5定位

css 一.定位1.概念&#xff08;定位定位模式边位移&#xff09;2.静态位移static&#xff08;不常用&#xff09;3.相对定位relative&#xff08;不脱标&#xff09;&#xff08;占位置&#xff09;4.绝对定位absolute&#xff08;脱标&#xff09;&#xff08;不占位置&#x…

Unity(第十七部)Unity自带的角色控制器

组件Character Controller 中文角色控制器 using System.Collections; using System.Collections.Generic; using UnityEngine;public class player : MonoBehaviour {private CharacterController player;void Start(){player GetComponent<CharacterController>();}v…

leetcode刷题(javaScript)——栈相关场景题总结

在LeetCode刷题中&#xff0c;栈是一个非常有用的数据结构&#xff0c;可以解决许多问题&#xff0c;包括但不限于以下几类问题&#xff1a; 括号匹配问题&#xff1a;例如检查括号序列是否有效、计算表达式的值等。逆波兰表达式求值&#xff1a;使用栈来实现逆波兰表达式的计算…