结构体
和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。可以当作是java对象。使用struct关键字定义
定义结构体
struct User {flag: bool,username: String,email: String,id: u32
}// 使用没有命名字段的元组结构体来创建不同的类型,称为元组结构体
struct Color(i32, i32, i32);// 类单元结构体
// 类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。
struct AlwaysEqual;
fn main() {let subject = AlwaysEqual;
}
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。
实例化
let mut user = User {flag: true,username: String::from("tom"),email: String::from("hello@email.com"),id : 1
};
// 使用.进行访问
user.flag = false;
//结构体更新语法,使用..复用
let user2 = User {username: String::from("jerry"),..user
};//使用没有命名字段的元组结构体来创建不同的类型,称为元组结构体
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);// 没有任何字段的类单元结构体
示例程序
struct Rectangle {width: u32,height: u32,
}fn main() {let rect1 = Rectangle {width: 30,height: 50,};println!("The area of the rectangle is {} square pixels.",area(&rect1));
}
fn area(rectangle: &Rectangle) -> u32 {rectangle.width * rectangle.height
}
方法
方法与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同
时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并且它们第一个参数总是 self ,它代表调用该方法的结构体实例
#[derive(Debug)]
struct Rectangle {width: u32,height: u32,
}
impl Rectangle {
//这里选择 &self 的理由跟在函数版本中使用 &Rectangle 是相同的:我们并不想获取所有权,只希望能够读取结构体中的数据,而不是写入。类似于使用指针fn area(&self) -> u32 {self.width * self.height}
}
fn main() {let rect1 = Rectangle {width: 30,height: 50,};println!("The area of the rectangle is {} square pixels.",rect1.area());
}
使用方法替代函数,除了可使用方法语法和不需要在每个函数签名中重复 self 的类型之外,其主要好处在于组织性。我们将某个类型实例能做的所有事情都一起放入 impl 块中,而不是让将来的用户在我们的库中到处寻找 Rectangle 的功能。
在 C/C++ 语言中,有两个不同的运算符来调用方法:. 直接在对象上调用方法,而 -> 在一个对象的指针上调用方法,这时需要先解引用指针。换句话说,如果 object 是一个指针,那么 object->something() 就像(*object).something() 一样。
Rust 并没有一个与 -> 等效的运算符;相反,Rust 有一个叫 自动引用和解引用的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。它是这样工作的:当使用 object.something() 调用方法时,Rust 会自动object 添加 & 、&mut 或 * 以便使 object 与方法签名匹配。这种自动引用的行为之所以有效,是因为方法有一个明确的接收者———— self 的类型。在给出接收者和方法名的前提下,Rust 可以明确地计算出方法是仅仅读取(&self ),做出修改(&mut self )或者是获取所有权(self )。
关联函数
所有在 impl 块中定义的函数被称为 关联函数(associated functions),因为它们与 impl 后面命名的类型相关。我们可以定义不以 self 为第一参数的关联函数(因此不是方法),因为它们并不作用于一个结构体的实例。我们已经使用了一个这样的函数:在 String 类型上定义
的 String::from 函数
struct Rectangle {width:u32,height:u32
}impl Rectangle {fn square(size: u32) -> Self {Self {width: size,height: size,}}
}fn main() {let sq = Rectangle::square(10);
}
关键字 Self 在函数的返回类型中代指在 impl 关键字后出现的类型,在这里是 Rectangle,每个结构体也允许有多个impl块