Rust 没有类的概念,它不包含传统面向对象编程语言中的类(class)关键字,而是通过结构体(struct)、特质(trait)和实现块(impl)等机制来实现类似面向对象的功能。
定义一个结构体
几乎所有有结构体这个概念的语言,定义结构体的关键字都是一样的,那就是struct。
由于结构体是一个集合,也就是复合类型。结构体中的所有元素/字段也必须明确指明它的数据类型。
定义一个结构体的语法格式如下
struct Name_of_structure {
field1:data_type,
field2:data_type,
field3:data_type
}
定义一个结构体时:
- 结构体名 Name_of_structure 和元素/字段名 fieldN 遵循普通变量的命名语法。
- 结构体中中的每一个元素/字段都必须明确指定数据类型。可以是基本类型,也可以是另一个结构体。
struct Employee {
name:String,
company:String,
age:u32
}
结构体初始化
创建结构体的实例或者说结构体初始化本质上就是创建一个变量。使用 let 关键字创建一个变量。
创建结构体的一个实例和定义结构体的语法真的很类似。但说起来还是有点复杂,我们先看具体的语法
let instance_name = Name_of_structure {
field1:value1,
field2:value2,
field3:value3
};
从语法中可以看出,初始化结构体时的等号右边,就是把定义语法中的元素类型换成了具体的值。
结构体初始化,实则就是对结构体中的各个元素进行赋值。
如果要访问结构体实例的某个元素,我们可以使用 元素访问符,也就是 点号 ( . ),如果要访问 Employee 的实例 emp1 中的 name 元素,我们定义了一个有三个元素的结构体 Employee,然后初始化一个实例 emp1,最后通过元素访问符来访问 emp1 的三个元素。
struct Employee {
name:String,
company:String,
age:u32
}
fn main() {
let emp1 = Employee {
company:String::from("TutorialsPoint"),
name:String::from("Mohtashim"),
age:50
};
println!("Name is :{} company is {} age is {}",emp1.name,emp1.company,emp1.age);
}
修改结构体实例
修改结构体实例就是对结构体的个别元素 重新赋值。
结构体实例默认是 不可修改的,由于结构体实例也是一个使用 let 定义的变量。
如果要修改结构体实例,就必须在创建时添加 mut 关键字,让它变成可修改的。
struct Employee {
name:String,
company:String,
age:u32
}
let mut emp1 = Employee {
company:String::from("TutorialsPoint"),
name:String::from("Mohtashim"),
age:50
};
emp1.age = 40;
println!("Name is :{} company is {} age is
{}",emp1.name,emp1.company,emp1.age);
结构体作为函数的参数
结构体的用途之一就是可以作为参数传递给函数。
定一个结构体参数和定义其它类型的参数的语法是一样的。我们这里就不多介绍了,直接看范例
下面的代码定义了一个函数 display ,它接受一个 Employee 结构体实例作为参数并输出结构体的所有元素
//定义一个结构体
struct Employee {
name:String,
company:String,
age:u32
}
fn main() {
//初始化结构体
let emp1 = Employee {
company:String::from("TutorialsPoint"),
name:String::from("Mohtashim"),
age:50
};
let emp2 = Employee{
company:String::from("TutorialsPoint"),
name:String::from("Kannan"),
age:32
};
//将结构体作为参数传递给 display
display(emp1);
display(emp2);
}
// 使用点号(.) 访问符访问结构体的元素并输出它么的值
fn display( emp:Employee){
println!("Name is :{} company is {} age is
{}",emp.name,emp.company,emp.age);
}
结构体实例作为函数的返回值
Rust 中的结构体不仅仅可以作为函数的参数,还可以作为 函数的返回值。
函数返回结构体实例需要实现两个地方:
- 在 箭头 -> 后面指定结构体作为一个返回参数。
- 在函数的内部返回 结构体的实例
fn main() {
let emp1 = Employee{
company:String::from("TutorialsPoint"),
name:String::from("Mohtashim"),
age:50
};
let emp2 = Employee {
company:String::from("TutorialsPoint"),
name:String::from("Kannan"),
age:32
};
let elder = who_is_elder(emp1,emp2);
println!("elder is:");
display(elder);
}
//接受两个 Employee 的实例作为参数并返回年长的那个
fn who_is_elder (emp1:Employee,emp2:Employee)->Employee {
if emp1.age>emp2.age {
return emp1;
} else {
return emp2;
}
}
// 显示结构体的所有元素
fn display( emp:Employee) {
println!("Name is :{} company is {} age is {}",emp.name,emp.company,emp.age);
}
// 定义一个结构体
struct Employee {
name:String,
company:String,
age:u32
}
结构体中的方法
Rust 中的结构体可以定义方法 (method)。
方法 (method) 是一段代码的逻辑组合,用于完成某项特定的任务或实现某项特定的功能。
方法(method) 和 函数(function) 有什么不同之处呢?
简单的说:
- 函数( function) 没有属主,也就是归属于谁,因此可以直接调用。
- 方法( method ) 是有属主的,调用的时候必须指定 属主。
- 函数( function) 没有属主,同一个程序不可以出现两个一样签名的函数。
- 方法( method ) 有属主,不同的属主可以有着一样签名的方法。
定义方法时需要使用 fn 关键字。
结构体方法的 作用域 仅限于 结构体内部。
与 C++ 语言中的结构体的方法不同的是,Rust 中的结构体方法只能定义在结构体的外面。
impl 关键字最重大的作用,就是定义上面我们所说的方法的属主。所有被 impl My_struct 块包含的代码,都只属于 My_struct 这个结构。
impl 关键字是 implement 的前 4 个字母的缩写。意思是 实现。
结构体的普通方法(后面我们还会学到其它方法)时,第一个参数永远是 &self 关键字。self 是”自我”的意思,&self 永远表明着当前的结构体的一个实例。
这是不是可以带来其它的结构体方法的解释:结构体的方法就是用来操作当前结构体的一个实例的。
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 定义方法:判断当前矩形是否可以容纳另一个矩形
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 20,
height: 40,
};
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
}
&self 是结构体普通方法固定的第一个参数,其它参数则是可选的。
即使结构体方法不需要传递任何参数,&self 也是固定的,必须存在的。
由于结构体的方法是有属主的,所以调用的时候必须先指定 属主,调用格式为 属主.方法名(方法参数)。
// 定义一个长方形结构体
struct Rectangle {
width:u32, height:u32
}
// 为长方形结构体定义一个方法,用于计算当前长方形的面积
impl Rectangle {
fn area(&self)->u32 {
// 在方法内部,可以使用点号 `self.` 来访问当前结构体的元素。use the . operator to fetch the value of a field via the self keyword
self.width * self.height
}
}
fn main() {
// 创建 Rectangle 结构体的一个实例
let small = Rectangle {
width:10,
height:20
};
//计算并输出结构体的面积
println!("width is {} height is {} area of Rectangle is {}",small.width,small.height,small.area());
}
结构体的静态方法
Rust 中的结构体还可以有静态方法。
静态方法可以直接通过结构体名调用而无需先实例化。
结构体的静态方法定义方式和普通方法类似,唯一的不同点是 不需要使用 &self 作为参数。
静态方法和其它普通方法一样,参数是可选的。也就是可以没有参数。
静态方法可以直接通过结构体名调用,而无需先实例化。
结构体的静态方法需要使用 structure_name:: 语法来访问。
//声明结构体 Point
struct Point {
x: i32,
y: i32,
}
impl Point {
// 用于创建 Point 实例的静态方法
fn getInstance(x: i32, y: i32) -> Point {
Point { x: x, y: y }
}
// 用于显示结构体元素的普通方法
fn display(&self){
println!("x = {} y = {}",self.x,self.y );
}
}
fn main(){
// 调用静态方法
let p1 = Point::getInstance(10,20);
p1.display();
}