结构体的定义和实例化
结构体与数据类型一节中讨论的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些命名,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
定义结构体,需要使用 struct
关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段(field)。例如,示例 5-1 展示了一个存储用户账号信息的结构体。
文件名: src/lib.cairo
#[derive(Copy, Drop)]
struct User {
active: bool,
username: felt252,
email: felt252,
sign_in_count: u64,
}
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。
我们创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value
键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。
例如,我们可以如示例5-2所示声明一个特定的用户。
文件名: src/lib.cairo
#[derive(Copy, Drop)] struct User { active: bool, username: felt252, email: felt252, sign_in_count: u64, } fn main() { let user1 = User { active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1 }; }
为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 user1.email
。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 5-3 展示了如何改变一个可变的 User
实例中 email
字段的值。
文件名: src/lib.cairo
#[derive(Copy, Drop)] struct User { active: bool, username: felt252, email: felt252, sign_in_count: u64, } fn main() { let mut user1 = User { active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1 }; user1.email = 'anotheremail@example.com'; } fn build_user(email: felt252, username: felt252) -> User { User { active: true, username: username, email: email, sign_in_count: 1, } } fn build_user_short(email: felt252, username: felt252) -> User { User { active: true, username, email, sign_in_count: 1, } }
注意,整个实例必须是可变的;Cairo不允许我们只把某些字段标记为可变的。
与任何表达式一样,我们可以在函数主体的最后一个表达式中构造一个新的结构体实例,以隐式返回该新实例。
示例5-4显示了一个build_user
函数,该函数返回一个User
实例,并给出了电子邮件和用户名。active
字段的值为true
,sign_in_count
的值为1
。
文件名: src/lib.cairo
#[derive(Copy, Drop)] struct User { active: bool, username: felt252, email: felt252, sign_in_count: u64, } fn main() { let mut user1 = User { active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1 }; user1.email = 'anotheremail@example.com'; } fn build_user(email: felt252, username: felt252) -> User { User { active: true, username: username, email: email, sign_in_count: 1, } } fn build_user_short(email: felt252, username: felt252) -> User { User { active: true, username, email, sign_in_count: 1, } }
为函数参数起与结构体字段相同的名字是可以理解的,但必须重复email
和username
字段的名称和变量就有点乏味了。如果结构体有更多字段,重复每个名称就更加烦人了。幸运的是,有一个方便的简写语法!
使用字段初始化简写语法
因为示例 5-4 中的参数名与字段名都完全相同,我们可以使用字段初始化简写语法(field init shorthand)来重写 build_user
。如示例 5-5 所示,重写后其行为与之前完全相同,不过无需重复 username
和 email
了。
文件名: src/lib.cairo
#[derive(Copy, Drop)] struct User { active: bool, username: felt252, email: felt252, sign_in_count: u64, } fn main() { let mut user1 = User { active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1 }; user1.email = 'anotheremail@example.com'; } fn build_user(email: felt252, username: felt252) -> User { User { active: true, username: username, email: email, sign_in_count: 1, } } fn build_user_short(email: felt252, username: felt252) -> User { User { active: true, username, email, sign_in_count: 1, } }
这里,我们正在创建一个新的 User
结构体实例,它有一个名为 email
的字段。我们希望将email
字段的值设置为build_user
函数的email
参数中的值。因为email
字段和email
参数有相同的名字,我们只需要写email
而不是email: email
。