聊一聊Rust的结构体

因为最近在接触rust语言,所以随便记录下学习过程中遇到的一些有意思的点。实际上结构体在很多语言中都存在。rust的结构体和c/c++语言的结构体其实也是非常类似的。假如我们要定义一个存储帐号信息的结构体

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

可以看到其实和c/c++语言并没有什么区别。不仅如此,rust的结构体初始化(实例化)也是和c/c++类似的。例如:

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

如果需要从结构体中获取某个特定的值,可以使用.号。和其他变量一样,结构体实例默认也是不可变的。如果结构体是可变的,那么当我们要修改结构体中的值,我们可以这样做

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

这里和c/c++的结构体的做法是一样的。在c/c++的结构体中同样是通过.来访问数据的。有些人可能会提到->,这里我也想简单讨论下者两个符号。其实.->在功能上是相同的,都是用来访问成员变量(或成员函数)的。.用于普通变量的操作而->则用于指针变量的操作。即->在一个对象指针上调用方法,这时需要先解引用指针。也就是说,如果object是一个指针,那么object->something()(*object).something()一样。这里要提的一点是,.->也可以用在class里。事实上,c++的classstruct并没有本质的区别,它和struct的区别主要就在访问控制上。

为什么rust没有->呢?实际上rust有一个自动引用和解引用功能。在rust的方法调用里就会用到。

对于rust的结构体,还有一点需要注意的是数据的所有权。我们为什么选择自身拥有所有权的String类型而不是&str字符串slice类型。这里很重要的一点就是所有权。如果我们想要这个结构体拥有它所有的数据,那么要使整个结构体有效,其数据也得是有效的才行。

不过,结构体也可以存储被其他对象拥有的数据的引用,不过这样做就必须引入生命周期了,原因也很简单,我们需要用生命周期来保证结构体引用的数据的有效性和结构体本身保持一致。否则,有可能出现结构体里实际存储了无效的引用的情况。因此,如果不指定声明周期,在结构体里存储引用是无效的。例如下面这段代码:

struct User {username: &str,email: &str,sign_in_count: u64,active: bool,
}fn main() {let user1 = User {email: "someone@example.com",username: "someusername123",active: true,sign_in_count: 1,};
}

编译器会报错,并提示需要生命周期标识符。

结构体的调试

我们在编程中经常会通过打印数据来调试代码,然而,在c/c++中,我们是不能直接打印结构体数据的,然而rust提供了一个很实用的功能,能够直接通过println!宏来打印信息。我们只需要在结构体定义之前加上#[derive(Debug)]注解即可。这里Debug是一个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 }

如果我们把println!内的{:?}替换成{:#},输出结果就会变为

rect1 is Rectangle {width: 30,height: 50
}

虽然只是个小功能,不得不说还是非常方便的。

结构体方法

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

对于方法,想必大家都很熟悉,事实上我之前也提过structclass其实并没有本质的区别。而rust里的struct,从某种程度上来说就是c++里的class。我们为struct实现方法实际上和c++为class实现方法基本是一致的

#[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());
}

可以看到我们为了使area函数在Rectangle上下文中,我们开始了一个impl块,并使area函数位于impl块中,并且area函数的第一个参数是&self。如此我们就可以通过.号来调用area方法了。

之前我们提到在c++里调用方法有.->两种符号。当object是一个对象指针时,我们需要用->来解引用。但是rust里却没有->,因为rust有自动引用和解引用功能。方法调用就是rust中少数拥有这种行为的地方。
当使用 object.something()调用方法时,Rust 会自动为 object 添加&&mut*以便使 object 与方法签名匹配。即

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

是等价的。

关联函数

这个比较特殊,它是在impl块中,不以self函数作为参数的函数,但是它与结构体相关联,所以被称为关联函数。,注意,关联函数虽然在impl块中,但它是函数而不是方法,因为它并不作用于一个结构体实例。
通常使用结构体名字和::来调用关联函数(这里和c++的命名空间有异曲同工之妙),典型的例子就是String::from这个函数了。

总结

最后引用一段rust程序设计方法的总结

结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。方法允许为结构体实例指定行为,而关联函数将特定功能置于结构体的命名空间中并且无需一个实例。

零零散散的写了一些不知所云的东西,rust作为一个新语言,其实很多设计都借鉴了一些已有的语言,但是也解决了一些痛点。我有时候经常遇到一些说法"这个在c/c++/java…里也有,只要xxxx",实际上真的有人去xxxx吗?当然我作为一个比较浅薄的人来说,语言对我来讲就是一个工具,如果语言能够大大降低我写代码的心智负担,那就最好不过了。如果说现有的工具能通过某某方法就能实现某某功能,只是比较麻烦,这并不意味着新的在老工具基础上做了简单改进的新工具不该出现。毕竟,编程这件事本身也是为了偷懒而已啊!

聊一聊Rust的结构体相关推荐

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

    文章目录 使用字段初始化简写语法 使用结构体更新语法从其他实例创建实例 使用没有命名字段的元组结构体来创建不同的类型 没有任何字段的类单元结构体 结构体和我们在"元组类型"部分论过 ...

  2. Rust中对某个结构体实现方法于rust中的关联函数

    写法比较独特,但与go语言相差不了太多,都是为结构体单独进行方法的实现: struct Rectangle{width: u32,length:u32, } impl Rectangle{fn are ...

  3. 如何在结构体里面套结构体_Rust 学习笔记-13 Rust 结构体

    什么是结构体 数组用于表示值的同构集合.类似地,结构体是Rust中另一个用户定义的数据类型,它允许我们组合不同类型的数据项,包括另一个结构体.结构体将数据定义为键值对. 定义一个结构体 struct ...

  4. rust笔记5结构体

    结构体基础 结构体的基本定义方式和使用方式: struct User {username: String,email: String,sign_in_count: u64,active: bool, ...

  5. 2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[derive(Builder)] pub stru

    2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法. 宏使用如下: #[derive(Builder)] pub stru ...

  6. 我的RUST学习——【第五章 5-2】一个使用结构体的demo

    一个demo 我们现在利用结构体来实现一个计算长方形面积的代码. 我决定搞的面向对象一些,因此在这里使用结构体. struct Rectangle {width: u32,height: u32, } ...

  7. oracle 构造体数据修改,Rust结构体更新语法

    使用Struct更新语法从其他实例创建新实例. 当新实例使用旧实例的大部分值时,可以使用struct update语法.考虑两名员工employee1和employee2. 首先,创建Employee ...

  8. 14.结构体struct.rs

    //Rust 里 struct 语句仅用来定义,不能声明实例,结尾不需要 ; 符号,而且每个字段定义之后用 , 分隔#[derive(Debug)] struct Site {domain: Stri ...

  9. C# 中的只读结构体(readonly struct)

    翻译自 John Demetriou 2018年4月8日 的文章 <C# 7.2 – Let's Talk About Readonly Structs>[1] 在本文中,我们来聊一聊从 ...

最新文章

  1. 改名Meta俩月,脸书放弃虚拟现实操作系统:负责人跳槽谷歌
  2. oracle 数据导入导出
  3. [UE4]C++实现动态加载的问题
  4. 浅谈最优化问题的KKT条件
  5. 动环监控系统的组成都有什么呢?
  6. JS面向对象--你真的理解闭包了吗?
  7. HDU - 6186 CS Course(维护前缀+后缀)
  8. xtrabackup备份还原
  9. Hibernate-Criteria
  10. linux下mysql数据库基础及客户端命令详解
  11. 各种数据库的批量插入操作_Oracle
  12. 联想M7650DF加粉和重置/清零的正确方法
  13. python int转换为byte_Python int与byte类型相互转化
  14. PS去除图片上的文字
  15. matlab投资组合权重,【原创】投资组合风险-收益关系的Matlab实现
  16. matlab如何看历史,matlab创建有价值历史纪录.txt 源代码在线查看 - Matlab创建有价值历史纪录(完整版),matlab 常用的命令集锦。 资源下载 虫虫电子下载站...
  17. FlashFxp配置ftp
  18. 阿里资深架构师的学习之路
  19. Cleartext vs. Plaintext vs. Ciphertext vs. Plaintext vs. Clear Text
  20. 3、Azure Devops之Azure Repos篇

热门文章

  1. MapReduce 的核心知识点,你都 get 到了吗 ?(干货文章,建议收藏!)
  2. TVS管的定义及使用注意事项
  3. js阻止默认事件(a标签跳转),阻止事件冒泡
  4. Raspberry Pi 4B树莓派 |#入门教程02# 树莓派GPIO控制(Python、C)
  5. 煤矿自动化系统指的是什么_煤矿综合自动化系统解决方案
  6. 总结下自己的入门学黑之路
  7. 学习笔记-会话技术CookieSession
  8. linux查看文件是否是x86架构,Linux下查看系统架构类型的几种方法
  9. Excel常用函数记录
  10. 百度云非会员下载限速套路: