11、Structs(结构体)
Structs(结构体)
接下来开始第二章的学习,这一章我们准备用一个工单案例来展开,首先是关于工单的定义,它涉及到标题,描述信息和状态
我们可以使用String类型来表示他们(String类型是一个Rust标准库表示UTF-8编码文本的数据类型)
将这些信息组合到一起,表示一个单独的实体,就可以用到结构体,这里和C/C++,java里面的结构体,class类等非常像
定义一个结构体
struct
关键字可以定义一个Rust的自定义新类型
struct Ticket {
title: String,
description: String,
status: String
}
新类型通过将其他类型组合为字段来构建的。每个字段必须有一个名称和一个类型,用:
分隔。如果有多个字段,则用,
分隔这些字段
每个字段的类型不必保持一致,类型可以自定义,例如
struct Configuration {
version: u32,
active: bool
}
总的定义语法如下
struct <结构体名>{
<字段名>:<字段类型>,
<字段名>:<字段类型>,
...
<字段名>:<字段类型>
}
实例化
我们可以通过指定每个字段的值创建一个该结构体的实例
// Syntax: <StructName> { <field_name>: <value>, ... }
let ticket = Ticket {
title: "Build a ticket system".into(),
description: "A Kanban board".into(),
status: "Open".into()
};
这其实就等同于C/C++的struct <结构体名> <对象名>=…
我对这里的.into()
比较好奇,所以查阅了一下资料,这里的.into()
其实就是Into<T>
trait 提供的方法,它允许我们将一种类型「转换」成另一种类型(通常是通过所有权转移或类型转换)。
这里的字符串其实是字符串字面量,类型是&str
,.into()
将字符串字面量转换为了String
类型。
访问字段
我们可以通过.
操作符来访问结构体里的字段,这是一种很常规的做法
// Field access
let x = ticket.description;
方法
Rust 中的结构体的方法是在一个 impl 代码块中定义的函数。方法是定义在 impl
代码块中的涵数,可以使用 self
作为第一个参数来操作一个结构体的实例。
impl Ticket {
fn is_open(self) -> bool {
self.status == "Open"
}
}
// Syntax:
// impl <StructName> {
// fn <method_name>(<parameters>) -> <return_type> {
// // Method body
// }
// }
调用方法时,直接用实例化出来的struct对象用.
操作符访问方法即可
bool if_open = ticket.is_open();
注意这里的方法和函数概念有一些区别
在rust中,方法尤指结构体里定义的函数,函数只是单指函数
项目 | Functions (函数) |
Methods (方法) |
---|---|---|
是否绑定到类型? | ❌ 否 | ✅ 是(通常通过 impl 块) |
拥有 self 参数吗? |
❌ 一般没有 | ✅ 有(self , &self , &mut self ) |
调用方式? | 直接调用 func() |
通过点语法调用 obj.method() |
作用域? | 全局或模块级 | 属于某个类型(struct/enum/trait) |
示例 | println!() |
ticket.is_open() |
他们最核心的两个不同是:
- 方法必须被定义在
impl
代码块 - 方法必须使用
self
作为它的第一个参数(self 是一个关键字,代表方法被调用的结构体的实例。)
self
如果方法的第一个参数是 self,则可以使用方法调用语法调用该方法:
// Method call syntax: <instance>.<method_name>(<parameters>)
let is_open = ticket.is_open();
静态方法
如果方法的第一个参数不是self
,那么这个方法就是静态方法
struct Configuration {
version: u32,
active: bool
}
impl Configuration {
// `default` is a static method on `Configuration`
fn default() -> Configuration {
Configuration { version: 0, active: false }
}
}
只有一种方式可以调用静态方法,就是使用function call syntax(函数调用语法)
// Function call syntax: <StructName>::<method_name>(<parameters>)
let default_config = Configuration::default();
调用的语法就是<结构体名>::<方法名>(参数)
等价方式
可以把self
作为静态方法的第一个参数来实现方法调用
// Function call syntax:
// <StructName>::<method_name>(<instance>, <parameters>)
let is_open = Ticket::is_open(ticket);
函数调用语法很清楚地表明,ticket 是作为方法的第一个参数 self 使用的,但肯定更啰嗦。在可能的情况下,我们更倾向于使用方法调用语法。
注意,这个等价方法的前提依然是结构体内部的方法的第一个参数是self才可以
经过查阅资料,我发现了 .操作符
其实就是 ::<方法名>(实例化的struct对象)
的语法糖,rust编译时会自动执行这个操作
练习
这一章节的练习感觉慢慢的开始有意思起来了,
我们要做的是定义一个Order结构体,里面有price和quantity两个字段,冰然它们的类型是无符号整型,我这里就让他们是u32好了
如果quantity>0就输出true,否则输出false,看到下面的代码,它使用了点操作符,那么我们就应该创建一个Order的impl代码实现块来完成这个方法
代码也挺好写的
struct Order{
price:u32,
quantity:u32
}
impl Order{
fn is_available(&self) -> bool{
if self.quantity>0{
true
}
else{
false
}
}
}
也是顺利的通过了
这一节的学习就先到这里了