复合数据类型
复合数据类型有数组、元组、结构体和枚举。
数组
rust
// let 数组变量名 : [类型; 元素个数];
let a: [i32; 3];
// 数组初始化
a = [4, 5, 6];
// 简化
let a = [1, 2, 3];
// 输出数组
println!("a = {:?}", a);
// 竖着输出数组
println!("{:#?}", a);
// 或者数组长度
println!("a.len() = {}", a.len());
// 默认初始值(默认值为5)
let a = [5; 3];
println!("a = {:?}", a);
rust
let a = [1, 2, 3, 5, 6];
// 指定位置到指定位置
let slice = &a[1..3]; // [2, 3]
println!("slice = {:?}", slice);
// 指定位置到结束
let slice = &a[3..]; // [5, 6]
println!("slice = {:?}", slice);
// 从开始到指定位置
let slice = &a[..2]; // [1, 2]
println!("slice = {:?}", slice);
rust
let matrix = [[1, 2, 3], [4, 5, 6]];
println!("{:#?}", matrix);
// 获取矩阵的行数
let row_num = matrix.len();
// 通过下标的方式获取元素
let row_1_col_2 = matrix[1][2];
println!("row_1_col_2 = {}", row_1_col_2);
元组
元组是固定长度的数据集合,每个元素可以是不同的类型。
rust
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("tup.0 is: {}", tup.0); // 访问元组的单个元素
println!("tup.1 is: {}", tup.1); // 访问元组的单个元素
println!("tup.2 is: {}", tup.2); // 访问元组的单个元素
let (x, y, z) = tup; // 解构元组
println!("The value of y is: {}", y); // 打印y
println!("The value of tup is: {:?}", tup); // 输出元组
// 嵌套元组
let tup2: (i32, (i32, i32), i32) = (1, (2, 3), 4);
println!("tup2.1.0 is: {}", tup2.1.0);
// 打印元组
println!("{:#?}", tup2);
结构体类型
结构体(Struct)是一种自定义类型,它包含多个字段,每个字段都有自己的类型。
rust
// 结构体定义
#[derive(Debug)] // 方便打印结构体
struct User {
name: String,
age: i32,
email: String,
}
// 结构体实例化
let user1 = User {
name: String::from("John"),
age: 30,
email: String::from("john@example.com"),
};
// 打印结构体(需要增加#[derive(Debug)])
println!("User1: {:?}", user1);
// 快速赋值
let user2 = User {
name: String::from("Mic"),
..user1
};
println!("User2: {:?}", user2);
rust
struct Rectangle {
width: u32,
height: u32,
}
// 定义方法
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("The area of the rectangle is {} square pixels.", rect.area());
}
rust
struct Circle {
radius: f64,
}
impl Circle {
// 关联函数new
fn new(radius: f64) -> Circle {
Circle { radius }
}
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
fn main() {
let circle = Circle::new(5.0); // 使用关联函数创建实例
println!("The area of the circle is {}", circle.area());
}
结构体的注意事项
- 字段的可见性是私有的,除非使用
pub
关键字标记。 - 结构体的大小是在编译时确定的,注意结构体的字段类型和顺序。
- 结构体可以使用模式匹配来解构和访问字段。
rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let origin = Point { x: -1, y: -1 };
match origin {
Point { x, y: 0 } => println!("On the x axis at {}", x),
Point { x: 0, y } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
// _ => println!("On both axis"), // collectively making this unreachable
}
}
枚举类型
枚举类型(Enum)是一种特殊的数据类型,特别适合表达“可数的有限集合”
rust
#[derive(Debug)] // 可以调试输出
enum IpAddrKind {
V4, // 变体(Variant)
V6,
}
// 打印枚举
println!("{:?}", IpAddrKind::V4);
rust
#[derive(Debug)]
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
fn main() {
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
println!("{:?}", home);
println!("{:?}", loopback);
}
Some类型
在Rust中,Some类型是枚举Option的一个枚举值,它表示一个值存在,而None则表示一个值不存在。
trait(特性、特质)
类似其他语言的接口,trait定义了一个可以被共享的行为,只要实现了trait,就能使用该行为
rust
trait Shape {
fn area(&self) -> f64;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
// 匿名的trait
impl Circle {
// 内在方法(Inherent Method)
fn get_radius(&self) -> f64 {
self.radius
}
}
fn main() {
let circle = Circle { radius: 5.0 };
println!("The area of the circle is {}", circle.area());
}
rust
trait Shape {
fn area(self: Box<Self>) -> f64;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
// Self的类型是Circle
// self的类型是Box<Circle>
fn area(self: Box<Self>) -> f64 {
// 访问成员变量,需要使用 self.radius
std::f64::consts::PI * self.radius * self.radius
}
}
fn main() {
let circle = Circle { radius: 5.0 };
let circle_box = Box::new(circle);
println!("The area of the circle is {}", circle_box.area());
}
rust
#[derive(Debug)]
struct T(i32);
impl T {
fn func(this: &Self) {
println!("value {:?}", this);
}
}
fn main() {
let t = T(1);
// t.func(); // 不能用这种方法调用
T::func(&t); // 静态方法调用
}
rust
pub trait Default {
fn default() -> Self;
}
impl<T> Default for Vec<T> {
fn default() -> Self {
Vec::new()
}
// fn default() -> Vec<T> {
// Vec::new()
// }
}
fn main() {
let v: Vec<i32> = Default::default();
println!("{:?}", v);
}
rust
trait Double {
fn double(&self) -> Self;
}
impl Double for i32 {
fn double(&self) -> Self {
*self * 2
}
}
fn main() {
let x: i32 = 5.double();
println!("{}", x);
}
rust
trait Cook {
fn start(&self);
}
trait Wash {
fn start(&self);
}
struct Cooker;
impl Cook for Cooker {
fn start(&self) {
println!("Cooking...");
}
}
impl Wash for Cooker {
fn start(&self) {
println!("Washing...");
}
}
fn main() {
let cooker = Cooker;
// note: candidate #2 is defined in an impl of the trait `Wash` for the type `Cooker`
// cooker.start();
// 需要指定完整函数调用方法
<Cooker as Wash>::start(&cooker);
<Cooker as Cook>::start(&cooker);
}
trait约束和继承
Rust的trait的另一大用处是作为泛型约束使用。
rust
fn my_print<T: std::fmt::Debug>(value: T) {
println!("The value is {:?}", value);
}
fn main() {
my_print(5);
my_print("Hello, world!");
my_print(true);
my_print(vec![1, 2, 3]);
}
rust
fn my_print<T>(value: T)
where T: std::fmt::Debug
{
println!("The value is {:?}", value);
}
fn main() {
my_print(5);
my_print("Hello, world!");
my_print(true);
my_print(vec![1, 2, 3]);
}
rust
trait Base {}
trait Derived : Base {}
struct T;
impl Derived for T {}
// | ^ the trait `Base` is not implemented for `T`
// 加上这个,编译器就不报错了
impl Base for T {}
fn main() {
let t = T;
let _: &dyn Derived = &t;
}
derive属性
通过impl实现trait,逻辑非常机械化,非常枯燥。
通过derive属性,可以自动实现一些常用功能,如Debug、Clone、Copy等。
rust
#[derive(Debug, Copy, Default, Eq)]
struct Foo {
x: i32,
}
fn main() {
let foo = Foo { x: 5 };
let foo2 = foo;
println!("{:?}", foo2);
}
Rust目前支持的derive属性有:
- Clone
- Copy
- Debug
- Eq
- Default
- Hash
- Ord
- Send
- Sync
- PartialEq
- PartialOrd
trait别名
rust
trait MyTrait = std::fmt::Debug + std::cmp::PartialEq;
fn my_print<T: MyTrait>(value: T) {
println!("The value is {:?}", value);
}
fn main() {
my_print(5);
}
特殊的trait
Sized
:表示类型有固定大小,如i32、str等,只能有编译器推导出来,用户无权指定。- 默认trait:
Copy
、Drop
、Default
等。