结构体(Struct)

我们需要为每个工单追踪三部分信息:

  • 标题
  • 描述
  • 状态

我们可以先使用 String 来表示它们。String是Rust标准库中定义的类型,用于表示UTF-8编码的文本。

但是,我们如何将这三部分信息合并为一个实体呢?

定义一个struct

struct定义了一个新的Rust类型

#![allow(unused)]
fn main() {
struct Ticket {
    title: String,
    description: String,
    status: String,
}
}

struct与你在其他编程语言中称为类或对象的东西非常相似。

定义字段

新类型是通过组合其他类型作为字段建立的。
每个字段都需要一个名字和一个类型,中间用冒号分隔开::如果有多个字段,则用逗号,分隔开。

字段不必是同一类型,如下面的Configuration结构体所示:

#![allow(unused)]
fn main() {
struct Configuration {
    version: u32,
    active: bool,
}
}

实例化

通过为每个字段指定值可以创建一个struct的实例:

#![allow(unused)]
fn main() {
// 语法:<StructName> { <field_name>: <value>, ... }
let ticket = Ticket {
    title: "建立一个工单系统".into(),
    description: "创建一个可以在看板上管理工单的系统".into(),
    status: "打开".into()};
}

访问字段

你可以使用.操作符访问struct的字段:

#![allow(unused)]
fn main() {
// 字段访问
let x = ticket.description;
}

方法

我们可以通过定义方法为我们的struct附加行为。
Ticket结构体为例:

#![allow(unused)]
fn main() {
impl Ticket {
    fn is_open(&self) -> bool {
        self.status == "Open"
    }
}

// 语法:
// impl <StructName> {
//    fn <method_name>(&self, <parameters>) -> <return_type> {
//        // 方法体
//    }
// }
}

方法与函数很相似,但有两个关键区别:

  1. 方法必须在**impl块内定义
  2. 方法可以使用self作为它们的第一个参数。 self是一个关键字,代表调用其调用方法的struct实例。

self

如果方法以self作为其第一个参数,它可以使用方法调用语法调用:

#![allow(unused)]
fn main() {
// 方法调用语法: <instance>.<method_name>(<parameters>)
let is_open = ticket.is_open();
}

这与上一章中对u32值执行饱和算术操作使用的调用语法相同02_basic_calculator/09_saturating.md

静态方法

如果方法不以self作为其第一个参数,它是一个静态方法

#![allow(unused)]
fn main() {
struct Configuration {
    version: u32,
    active: bool,
}

impl Configuration {
    // `default` 是 `Configuration` 上的静态方法
    fn default() -> Configuration {
        Configuration { version: 0, active: false }
    }
}

调用静态方法的唯一方式是使用函数调用语法

#![allow(unused)]
fn main() {
// 函数调用语法: <StructName>::<method_name>(<parameters>)
let default_config = Configuration::default();
}

等价性

即使以self作为第一个参数的方法,你也可以使用函数调用语法:

#![allow(unused)]
fn main() {
// 函数调用语法: <StructName>::<method_name>(<instance>, <parameters>)
let is_open = Ticket::is_open(ticket);
}

函数调用语法清晰地表明ticket作为self,方法的第一个参数在使用,但确实更冗长。可能时优先使用方法调用语法。

参考资料

  • 本节练习位于 exercises/03_ticket_v1/01_struct