Structs相似于ts中的Interface,权且称之为构造吧。在rust中它跟tuple十分类似。与元组不同的是,咱们能够为每个数据命名,以便分明地晓得这些值的含意。 因为应用了这些名称,因而构造比元组更灵便:不用依赖数据的程序来指定或拜访实例的值。
废话少说,先来一个structs的实例:
struct User { username: String, email: String, sign_in_count: u64, active: bool,}
要定义一个构造,咱们输出关键字struct并命名整个构造。 构造的名称应阐明将数据分组在一起的重要性。 而后,在大括号内,定义数据片段的名称和类型,咱们将其称为字段。struct的应用,十分相似于interface,比方应用下面定义的User,相似于ts中定于一个特定的对象:
#[derive(Debug)]struct User { username: String, email: String, sign_in_count: u64, active: bool,}fn main() { let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; println!("{:?}", user1)}cargo run User { username: "someusername123", email: "someone@example.com", sign_in_count: 1, active: true }
留神想要把构造实例打印进去必须在应用struct的下面增加一行#[derive(Debug)]
,否则就会报错。
那么,如何应用和扭转一个构造实例中的属性呢?看实例:
println!("{:?}", user1.email);//如果定义的实例是一个可变变量的话,那么能够扭转其属性值。//let mut user1 = User {...}user1.email = String::from("test@example.com");println!("{:?}", user1.email);cargo run "someone@example.com" "test@example.com"
是否能够向js中的工厂办法来获取实例呢,能够的,例如:
fn build_user(email: String, username: String) -> User { User { email: email, username: username, active: true, sign_in_count: 1, }}fn main() { let user1 = build_user( String::from("someone@example.com"), String::from("someusername123"), ); println!("{:?}", user1)}cargo run User { username: "someusername123", email: "someone@example.com", sign_in_count: 1, active: true }
留神想要扭转实例的某个属性的时候整个实例必须是可变的。 Rust不容许咱们仅将某些字段标记为可变字段。 与任何表达式一样,咱们能够结构该构造的新实例作为函数主体中的最初一个表达式,以隐式返回该新实例。
特地,如果构造方法中含有固定的属性值,且当变量和字段具备雷同名称时,应用字段初始化速记:
fn build_user(email: String, username: String) -> User { User { email, username, active: true, sign_in_count: 1, }}fn main() { let user1 = build_user( String::from("someone@example.com"), String::from("someusername123"), );}
在上述例子中,咱们正在创立User构造的新实例,该实例具备一个名为email的属性, 咱们想将email属性的值设置为build_user函数的email参数中的值。 因为email字段和email参数具备雷同的名称,所以咱们只须要编写email而不是email:email。
此外咱们还能够应用构造更新语法从其余实例创立实例
fn main() { let user1 = build_user( String::from("someone@example.com"), String::from("someusername123"), ); let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), active: user1.active, sign_in_count: user1.sign_in_count, }; println!("{:?}", user1); println!("{:?}", user2);}cargo run User { username: "someusername123", email: "someone@example.com", sign_in_count: 1, active: true } User { username: "anotherusername567", email: "another@example.com", sign_in_count: 1, active: true }
另外,应用struct update语法,咱们能够用更少的代码来达到雷同的成果,如下实例用法。 语法..指定未明确设置的其余字段应与给定实例中的字段具备雷同的值:
//与上例的后果截然不同let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), ..user1 };
应用没有命名字段的元组构造创立不同的类型
咱们还能够定义看起来相似于元组的构造,称为元组构造。元组构造具备附加的含意,即构造名称提供的含意,但没有与其字段关联的名称; 相同,它们只是字段的类型。 当咱们想给整个元组起一个名字并使元组成为与其余元组不同的类型时,元组构造很有用,并且像惯例构造中那样命名每个字段都是简短或多余的。
要定义元组构造,与下面实例相似,以struct关键字和构造名称结尾,后跟元组中的类型。 例如,以下是两个名为Color和Point的元组构造的定义和用法:
#[derive(Debug)]struct Color(i32, i32, i32);#[derive(Debug)]struct Point(i32, i32, i32);fn main() { let black = Color(0, 0, 0); let origin = Point(0, 0, 0); println!("{:?}", black); println!("{:?}", origin);}cargo run Color(0, 0, 0) Point(0, 0, 0)
留神,black和origin是不同的类型,因为它们是不同元组构造的实例。咱们定义的每个构造都是其本人的类型,即便该构造中的字段具备雷同的类型。 例如,即便两个类型都由三个i32值组成,然而采纳Color类型参数的函数也不能将Point作为参数。因而,元组struct实例的行为就像元组:能够将它们合成为独自的片段,能够应用。而后用索引以拜访单个值,依此类推。
没有任何字段的相似单元的构造
咱们还能够定义没有任何字段的构造! 这些被称为类单元构造,因为它们的行为相似于单元类型()。 在须要在某种类型上实现特色但又不想在类型自身中存储任何数据的状况下,相似单元的构造很有用。
构造数据的所有权
在上述例子的User struct定义中,咱们应用领有的String类型而不是&str字符串切片类型。 其起因是咱们心愿该构造的实例领有其所有数据,并且只有整个构造无效,该数据就始终无效。
构造可能会存储对其他人领有的数据的援用,但这样做须要应用生命周期。作为构造生命周期可确保构造所援用的数据在很长的工夫内无效。假如咱们尝试将援用存储在构造中,但未指定生命周期,例如这样,将有效:
struct User { username: &str, email: &str, sign_in_count: u64, active: bool,}fn main() { let user1 = User { email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1, };}$ cargo run |2 | username: &str, | ^ expected lifetime parametererror[E0106]: missing lifetime specifier --> src/main.rs:3:12 |3 | email: &str, | ^ expected lifetime parametererror: aborting due to 2 previous errorsFor more information about this error, try `rustc --explain E0106`.error: could not compile `structs`.To learn more, run the command again with --verbose.