【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据

这篇具有很好参考价值的文章主要介绍了【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据


前言

本章节讲解一种自定义数据类型:结构体,它允许将多个相关的值打包在一起命名,如果你熟悉面向对象语言,那么结构体就像类一样。

主要教材参考 《The Rust Programming Language》


一、定义和实例化结构

1.1、定义结构

要定义结构体,使用关键字 struct 并为结构命名。结构体的名称应该描述组合在一起的数据的重要性。另外打括号包括起来的数据名称和类型,我们称之为字段。

例子:user 结构定义

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

1.2、实例化结构

我们在定义结构后要使用它,需要为每个字段指定具体的值,从而创建该结构的实例,然后添加包含键值对的花括号,其中键就是字段的名称,值就是我们希望存储在这些字段中的数据。

我们不必按照在结构体中声明字段的顺序指定字段。结构定义就像该类型的通用模板,实例用特定的数据填充该模板,以创建该类型的值。

范例:结构的实例化

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

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

1.3、访问和修改结构体变量的成员

我们要读或写对象的成员,可以使用 变量.字段 的形式来来问。如果要想修改结构体成员的值,我们必须 使用mut 标记结构体。

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

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

  println!(" user's email is {}", user.email);
  user.email = String::from("anotheremail@example.com");

  println!(" user's active is {}", user.active);
  println!(" user's username is {}", user.username);
  println!(" user's email is {}", user.email);
  println!(" user's sign_in_count is {}", user.sign_in_count);
}

1.4、函数与结构

1.4.1、使用函数实例化用户


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

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

fn main() {
  let email:String = String::from("xiaojia@example.com");
  let username:String = String::from("xiaojia");
  let mut user:User = build_user(email, username);
  
  println!(" user's email is {}", user.email);
  user.email = String::from("anotheremail@example.com");

  println!(" user's active is {}", user.active);
  println!(" user's username is {}", user.username);
  println!(" user's email is {}", user.email);
  println!(" user's sign_in_count is {}", user.sign_in_count);
}

1.4.2、结构体支持精简的实例化

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

1.5、用一个结构体去创建另一个结构体

1.5.1、用结构体成员实例化结构

  let email:String = String::from("xiaojia@example.com");
  let username:String = String::from("xiaojia");
  let user01:User = build_user(email, username);

  let user02:User = User { 
    active: user01.active, 
    username: user01.username, 
    email: String::from("another@example.com"),
    sign_in_count: user01.sign_in_count
  };

1.5.2、结构体更新(struct update)的语法

  let email:String = String::from("xiaojia@example.com");
  let username:String = String::from("xiaojia");
  let user01:User = build_user(email, username);
  let user02:User = User { 
    email: String::from("another@example.com"),
    ..user01
  };

结构体更新语法使用 = 就像赋值,这是因为它移动数据,在创建 user02 之后,我们不能再将 user01 作为一个整体使用,因为 user01 的 username 被移到了 user02 中了。

但是 active 和 sign_in_count 值,在创建 user02 之后 在 user01 之中仍然有效。

1.6、使用未命名字段的元组创建不同的类型(Tuple struct)

tuple- struct 是 Rust 对 struct 关键字的一个创新,可以将 Tuple Struct 理解为非匿名的tuple。

#[allow(dead_code)]
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
	
	// 使用 模式解构 方式来获取值,我们称之为 newtype parttern
    let Point(x, y, z) = origin;  
    
    // 使用索引方式来获取值
    let length = origin.0;
    let width = origin.1;
    let heigth =  origin.2;
}

1.7、Unit-Like Struct

在 Rust 中可以定义没有任何字段的 struct,叫做 Unit-Like Struct。 适用于需要在某个类型上实现某个 trait,但是在里面又没有想要存储的数据。

struct AlwaysEqual;

fn main() {
    let subject = AlwaysEqual;
}

1.8、Struct 数据的所有权

Struct 里面如果不是存放的引用,那么该 struct 实例拥有其所有的数据,只要 struct 实例是有效的,那么里面的字段数据也是有效的;

struct 里面也可以存放引用,但这需要使用生命周期

  • 生命周期保证只要 struct 实例是有效的,那么里面的引用也是有效的;
  • 如果 struct 里面存储引用,而不是用生命周期,就会报错;
error[E0106]: missing lifetime specifier
 --> src/main.rs:3:13
  |
3 |   username: &str,
  |             ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
1 ~ struct User<'a> {
2 |   active: bool,
3 ~   username: &'a str,
  |

二、使用结构的例子

2.1、简单的长方形面积的例子

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

fn main() {
  let rect = Rectangle{
    width: 30,
    length: 50,
  };
  println!("{}", area(&rect));
}

fn area(rect : & Rectangle) -> u32 {
  rect.width * rect.length
}

2.2、用 派生的Trait 添加功能

2.2.1、使用 println! 宏来打印结构信息

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

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

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

此时结构体不能直接打印 结构体的内容。

error[E0277]: `Rectangle` doesn't implement `std::fmt::Display`
  --> src/main.rs:12:27
   |
12 |   println!("rect1 is {}", rect1);
   |                           ^^^^^ `Rectangle` cannot be formatted with the default formatter
   |
   = 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
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

根据提示我们用 {:?}{:#?} 格式来替代或者 实现 std::fmt::Display

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

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

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

此时,还是会有如下的错误提示:

error[E0277]: `Rectangle` doesn't implement `Debug`
  --> src/main.rs:12:29
   |
12 |   println!("rect1 is {:?}", rect1);
   |                             ^^^^^ `Rectangle` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `Rectangle`
   = note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle`
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Rectangle` with `#[derive(Debug)]`
   |
1  + #[derive(Debug)]
2  | struct Rectangle {

上述提示我们使用 #[derive(Debug)] 来派生或者手动实现 Debug。

#[allow(unused)] // 允许变量不使用 抑制警告
#[derive(Debug)]
struct Rectangle {
  width: u32,
  height: u32,
}

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

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

如果你的struct 很复杂,可以是用 {:#?} 可以格式化显示结构体

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

2.2.2、使用 dbg! 宏来打印结构信息

我们使用 println! 宏来打印调试信息的时候,并不会打印文件名,所在行号,如果要调试的时候方便可以使用 dbg! 打印 结构体的信息,需要注意的是 该宏需要实现 Debug 接口。

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

fn main() {
  let scale = 2;
  let rect1 = Rectangle {
      width: dbg!(30 * scale),
      height: 50,
  };

  dbg!(&rect1);
}

三、 方法语法

3.1、结构普通方法

使用 impl 关键字可以为结构定义方法,方法的第一个参数是 &self 或者 self 相当于别的语言的 this 指针。

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

impl Rectangle{
  fn area(&self)-> u32 {
    self.width * self.height
  }
}

fn main() {
  let scale = 2;
  let rect1 = Rectangle {
      width: dbg!(30 * scale),
      height: 50,
  };

  dbg!(&rect1.area());
}

在调用方法时, Rust 会根据情况自动添加 & 、&mut 或者* ,以便 object 可以匹配方法的签名。

3.2、关联函数(Associated Functions)

例如我们可以在 impl 代码块里面定义不把 self 作为第一个参数的函数,它们叫做关联函数:例如 String:from();

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

impl Rectangle{
  fn area(&self)-> u32 {
    self.width * self.height
  }

  fn square(size: u32) -> Self{
    Self { 
      width: size, 
      height: size,
     }
  }
}

fn main() {
  let s = Rectangle::square(20);
  dbg!(s.area());
  dbg!(s);
}

3.3、Multiple impl Blocks

一个结构可以有多个 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
    }
}

总结

以上就是今天要讲的内容文章来源地址https://www.toymoban.com/news/detail-497661.html

  • 本章我们讲解了如何定义结构、如何使用结构、如何定义方法、关联函数等。

到了这里,关于【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python序列化和结构化数据详解

    序列化和结构化数据是计算机程序中非常重要的概念,它们的原理和应用在许多应用程序中都是必不可少的。Python作为一种高级编程语言,在序列化和结构化数据方面提供了很多优秀的解决方案。在本文中,我们将详细介绍Python中序列化和结构化数据的相关概念和应用。 1.

    2024年02月08日
    浏览(61)
  • 结构化数据处理与分析:Spark SQL 教程

    作者:禅与计算机程序设计艺术 Apache Spark 是由 Apache 基金会开发的开源分布式计算框架,最初用于对大规模数据进行快速的处理,在大数据计算领域占据重要地位。其独特的高性能处理能力及丰富的数据处理功能使得 Spark 在各个行业应用广泛。Spark SQL 是 Spark 提供的用于结构

    2024年02月06日
    浏览(50)
  • 一种使得大模型输出结构化数据的简易方法

    最近在用大模型跑一些数据,于是就不可避免的遇到了如何让大模型输出的格式便于处理这个问题。经过一些研究发现了一套比较有用的方法,在这里总结一下。 任务是这样的,我需要用大模型(比如ChatGPT,ChatGLM等等)对文本进行名词提取。输入一段文本,我需要大模型理

    2024年02月16日
    浏览(41)
  • 13.JavaWeb & XML:构建结构化数据的重要工具

    目录 导语: 一、XML概念 (1)可拓展 (2)功能-存储数据 (3)xml与html的区别 二、XML内容 三、XML用途 四、案例:使用XML构建在线书店的书籍数据库 结语:     在当今的信息时代,数据结构化和管理成为了一个重要课题。XML(eXtensible Markup Language,可扩展标记语言)作为一

    2024年04月09日
    浏览(50)
  • StarRocks 生成列:百倍提速半结构化数据分析

    半结构化分析主要是指对 MAP,STRUCT,JSON,ARRAY 等复杂数据类型的查询分析。这些数据类型表达能力强,因此被广泛应用到 OLAP 分析的各种场景中,但由于其实现的复杂性,对这些复杂类型分析将会比一般简单类型要更困难和耗时,例如: 需要对 MAP,STRUCT,JSON 等数据类型中

    2024年01月22日
    浏览(61)
  • 用ChatGPT解读非结构化数据【ChatGPT + SQL】

    许多现代数据系统都依赖于结构化数据,例如 Postgres DB 或 Snowflake 数据仓库。 LlamaIndex 提供了许多由 LLM 提供支持的高级功能,既可以从非结构化数据创建结构化数据,也可以通过增强的文本到 SQL 功能分析这些结构化数据。 本指南有助于逐步了解这些功能中的每一项。 具体

    2023年04月21日
    浏览(37)
  • Verilog的三种描述方式(结构化描述、数据流描述、行为级描述对电路功能的描述有三种方式:结构化描述、数据流描述、行为级描述

    Verilog的三种描述方式(结构化描述、数据流描述、行为级描述对电路功能的描述有三种方式:结构化描述、数据流描述、行为级描述。三种描述方式抽象级别不同,各有优缺点,相辅相成,需要配合使用。 目录 一、结构化描述 1、概念 2、特点 3、示例 真值表: 电路抽象:

    2024年02月04日
    浏览(67)
  • ModaHub魔搭社区:非结构化数据范式转变和示例

    目录 范式转变——非结构化数据 非结构化数据示例 既然我们对结构化数据和半结构化数据有了清晰的理解,现在让我们开始谈谈非结构化数据。与结构化数据和半结构化数据不同,非结构化数据可以采取任何形式,可以有任意大小或尺寸,并需要大量的运行时间来转换和索

    2024年02月13日
    浏览(40)
  • 通过Siri打造智能爬虫助手:捕获与解析结构化数据

    在信息时代,我们经常需要从互联网上获取大量的结构化数据。然而,传统的网络爬虫往往需要编写复杂代码和规则来实现数据采集和解析。如今,在苹果公司提供的语音助手Siri中有一个强大功能可以帮助我们轻松完成这项任务——通过使用自定义指令、意图扩展以及快捷方

    2024年02月09日
    浏览(52)
  • 系统架构设计专业技能 ·结构化需求分析 - 数据流图

    现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. 点击进入系列文章目录 实体 实体可能是: (1)人物角色: 如客户、管理员、主管、经理、老师、学生 (2)组织机构 :如银行、供应商、募捐机

    2024年02月09日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包