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编译时会自动执行这个操作

练习

这一章节的练习感觉慢慢的开始有意思起来了,

image-20250831093804473

我们要做的是定义一个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
        }
    }
}

image-20250831094046818

也是顺利的通过了

这一节的学习就先到这里了

阅读剩余
THE END