基础篇-结构体

  • 木头
  • 更新于 2023-02-20 17:42
  • 阅读 1914

结构体实例创建和使用

结构体和我们在“元组类型”部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。

定义结构体,需要使用 struct 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段(field)。例如展示了一个存储用户账号信息的结构体:

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

一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。例如声明一个特定的用户:

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

fn main() {
    let user1 = User {
        active: true,
        name: String::from("张三"),
        email: String::from("www@qq.com"),
        sign_in_count: 1,
    };
}

为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的名称,可以用 user1.name。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。如何改变一个可变的 User 实例中 name 字段的值:

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

fn main() {
    let mut user1 = User {
        active: true,
        name: String::from("张三"),
        email: String::from("www@qq.com"),
        sign_in_count: 1,
    };

    user1.name = String::from("李四");
}

注意整个实例必须是可变的;Rust 并不允许只将某个字段标记为可变。另外需要注意同其他任何表达式一样,我们可以在函数体的最后一个表达式中构造一个结构体的新实例,来隐式地返回这个实例:

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

fn main() {
    let user1 = build_user(String::from("张三"), String::from("www@qq.com"));
}

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

build_user 函数,它返回一个带有给定的email 和用户名的 User 结构体实例。active 字段的值为true,并且 sign_in_count 的值为1

为函数参数起与结构体字段相同的名字是可以理解的,但是不得不重复 emailname 字段名称与变量有些啰嗦。如果结构体有更多字段,重复每个名称就更加烦人了。Rust提供方便的简写语法。

使用字段初始化简写语法

因为上面示例中的参数名与字段名都完全相同,我们可以使用 字段初始化简写语法(field init shorthand)来重写 build_user,这样其行为与之前完全相同,不过无需重复 nameemail了,如示例:

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

fn main() {
    let user1 = build_user(String::from("张三"), String::from("www@qq.com"));
}

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

这里我们创建了一个新的 User 结构体实例,它有一个叫做 email 的字段。我们想要将 email 字段的值设置为 build_user 函数 email 参数的值。因为 email 字段与 email 参数有着相同的名称,则只需编写 email 而不是 email: email

从其他结构体创建实例

使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过 结构体更新语法(struct update syntax)实现:

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

fn main() {
    let user1 = build_user(String::from("张三"), String::from("www@qq.com"));

    let user2 = User {
        active: user1.active,
        name: user1.name,
        email: String::from("www1@qq.com"),
        sign_in_count: user1.sign_in_count,
    };
}

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

user2 中创建一个新User 实例。我们为 email 设置了新的值,其他值则使用了user1 中的同名值。

使用结构体更新语法,我们可以通过更少的代码来达到相同的效果,.. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值:

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

fn main() {
    let user1 = build_user(String::from("张三"), String::from("www@qq.com"));

    let user2 = User {
        email: String::from("www1@qq.com"),
        ..user1
    };
}

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

user2 中创建了一个新实例,但该实例中 email 字段的值与 user1 不同,而 nameactivesign_in_count 字段的值与 user1相同。..user1 必须放在最后,以指定其余的字段应从 user1的相应字段中获取其值,但我们可以选择以任何顺序为任意字段指定值,而不用考虑结构体定义中字段的顺序。

元组结构体

元组结构体没有具体的字段名,只有字段的类型,使用圆括号。

要定义元组结构体,以 struct 关键字和结构体名开头并后跟元组中的类型。元组结构体的定义和用法:

struct Point(i32, i32);
fn main() {
    //创建
    let point = Point(10, 20);
    //取值
    println!("{},{}", point.0, point.1);
}

没有任何字段的类单元结构体

我们也可以定义一个没有任何字段的结构体!它们被称为 类单元结构体(unit-like structs)因为它们类似于(),类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。例子:

struct A();
fn main() {
    let a = A();
}

结构体打印

打印结构体需实现#[derive(Debug)]trait

#[derive(Debug)]
struct User {
    active: bool,
    name: String,
    email: String,
    sign_in_count: u64,
}

fn main() {
    let user1 = User {
        active: true,
        name: String::from("张三"),
        email: String::from("www@qq.com"),
        sign_in_count: 1,
    };

    println!("user1 = {:?}", user1);
    //格式打印
    println!("user1 = {:#?}", user1);
}
  • 原创
  • 学分: 8
  • 分类: Rust
  • 标签:
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
125 订阅 31 篇文章

0 条评论

请先 登录 后评论
木头
木头
0xC020...10cf
江湖只有他的大名,没有他的介绍。