Skip to content

复合数据类型

复合数据类型有数组、元组、结构体和枚举。

数组

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());
}

结构体的注意事项

  1. 字段的可见性是私有的,除非使用 pub 关键字标记。
  2. 结构体的大小是在编译时确定的,注意结构体的字段类型和顺序。
  3. 结构体可以使用模式匹配来解构和访问字段。
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:CopyDropDefault等。

人生感悟