Rust 笔记:Rust 语言中的 结构体 与面向对象编程的实现

Rust 笔记
Rust 语言中的 结构体

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
邮箱 :[email protected]
本文地址:https://blog.csdn.net/qq_28550263/article/details/130876493


【介绍】:本文先介绍 Rust 语言中的 结构体 的基本用法,然后重点介绍了在 Rust 语言中通过结构体实现面向对象编程的思想、方法并给出了相当多的代码示范。

上一节:《 Rust 语言中的 所有权 | 下一节:《 Rust 语言中的枚举

目 录

  • 1. 结构体入门
    • 1.1 什么是结构体
    • 1.2 结构体的定义和使用
    • 1.3 为什么使用结构体
    • 1.4 入门示例:定义一个简单的结构体
  • 2. 结构体中的成员
    • 2.1 成员变量
    • 2.2 成员方法
    • 2.3 进阶示例:定义包含变量和方法的结构体
  • 3. 结构体的实例化
    • 3.1 创建结构体实例
    • 3.2 结构体实例的初始化
    • 3.3 使用示例:实例化一个结构体并初始化
  • 4. 结构体的实现
    • 4.1 为结构体实现方法
    • 4.2 为结构体实现 trait
    • 4.3 示例:为结构体实现方法和 trait
  • 5. 结构体与面向对象
    • 5.1 面向对象的特点:抽象、封装、继承、多态
    • 5.2 结构体的继承
      • 5.2.1 tuple 结构体
      • 5.2.2 结构体的嵌套
      • 5.2.3 实战示例:结构体的继承和嵌套
    • 5.3 使用结构体描述对象
    • 5.4 与基于类描述对象的对比
      • 5.4.1 封装性
      • 5.4.2 继承性
      • 5.4.3 多态性
      • 5.4.4 所有权系统
  • 6. 总结


1. 结构体入门

1.1 什么是结构体

结构体是一种自定义的数据类型,它允许我们将不同类型的数据组合在一起,形成一个新的类型。

1.2 结构体的定义和使用

在Rust中,可以使用struct关键字来定义结构体,并在结构体内部定义其字段。

struct Person {
    name: String,
    age: u32,
}

上面的代码定义了一个名为Person的结构体,它有两个字段:name和age,分别对应字符串类型和无符号整数类型。

要创建结构体的实例,可以使用以下方式:

let person1 = Person {
    name: String::from("Alice"),
    age: 25,
};

在上面的示例中,我们创建了一个名为person1的Person结构体实例,并初始化了其字段的值。

1.3 为什么使用结构体

使用结构体可以将相关的数据组合在一起,形成一个有组织的数据结构。结构体可以提供更好的代码组织和可读性,同时还可以为结构体定义方法和实现特定的行为。

1.4 入门示例:定义一个简单的结构体

struct Point {
    x: f32,
    y: f32,
}

上述代码定义了一个名为Point的结构体,它有两个字段:x和y,类型为f32,即单精度浮点数。

我们可以创建该结构体的实例并访问其字段:

let origin = Point { x: 0.0, y: 0.0 };
println!("Origin: ({}, {})", origin.x, origin.y);

在上面的示例中,我们创建了一个名为origin的Point结构体实例,并通过.操作符访问了其字段的值。

通过结构体,我们可以方便地组合多个相关字段,形成自定义的数据类型,并使用这些类型的实例进行操作和访问。这样可以提高代码的可读性和可维护性,同时还能更好地组织数据和行为。

2. 结构体中的成员

2.1 成员变量

结构体中的成员变量用于存储不同类型的数据,例如整数、浮点数、字符串等。成员变量可以通过结构体实例的字段名来访问和操作。

struct Rectangle {
    width: u32,
    height: u32,
}

上述代码定义了一个名为Rectangle的结构体,它有两个成员变量:width和height,类型为u32,即无符号32位整数。

let rect = Rectangle {
    width: 10,
    height: 20,
};

在上面的示例中,我们创建了一个名为rect的Rectangle结构体实例,并初始化了其width和height成员变量的值。

println!("Width: {}", rect.width);
println!("Height: {}", rect.height);

通过 . 操作符,我们可以访问结构体实例的成员变量并获取其值。

2.2 成员方法

结构体可以定义成员方法,也称为关联函数。成员方法用于在结构体上执行特定的操作,可以访问结构体的成员变量和其他方法。

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

在上述代码中,我们通过impl块为Rectangle结构体实现了一个名为area的方法。该方法用于计算矩形的面积,它获取一个&self参数(即结构体实例的借用),并返回一个u32类型的值。

let rect = Rectangle {
    width: 10,
    height: 20,
};

println!("Area: {}", rect.area());

在上面的示例中,我们创建了一个名为rect的Rectangle结构体实例,并通过调用area方法计算了其面积。通过.操作符,我们可以在结构体实例上调用方法并获取返回值。

2.3 进阶示例:定义包含变量和方法的结构体

struct Circle {
    radius: f32,
}

impl Circle {
    fn new(radius: f32) -> Circle {
        Circle { radius }
    }

    fn area(&self) -> f32 {
        3.14 * self.radius * self.radius
    }
}
fn main() {
    let circle = Circle::new(5.0);
    println!("Area: {}", circle.area());
}

上述示例中,我们定义了一个名为 Circle 的结构体,它有一个成员变量 radius 表示半径。我们还为Circle结构体实现了一个关联函数 new 用于创建实例,并定义了一个成员方法 area 用于计算圆的面积。

在 main 函数中,我们使用 Circle::new 关联函数创建了一个 Circle 结构体实例,并通过调用 area 方法计算了其面积。

通过成员变量和成员方法,结构体提供了一种方便的方式来存储和操作数据。结构体的成员变量可以保存不同类型的数据,成员方法可以对结构体进行特定的操作,使得代码更加清晰和模块化。

3. 结构体的实例化

3.1 创建结构体实例

要创建结构体的实例,可以使用结构体名和初始化成员变量的值。

struct Car {
    make: String,
    model: String,
    year: u32,
}

上述代码定义了一个名为Car的结构体,它有三个成员变量:make、model和year,分别对应字符串类型和无符号32位整数类型。

let car = Car {
    make: String::from("Toyota"),
    model: String::from("Camry"),
    year: 2021,
};

在上面的示例中,我们创建了一个名为car的Car结构体实例,并初始化了其成员变量的值。通过在花括号中提供成员变量名和对应的值,我们可以对结构体进行初始化。

3.2 结构体实例的初始化

我们可以选择只对结构体的部分成员变量进行初始化。在初始化时,未指定的成员变量将使用默认值。

let car = Car {
    make: String::from("Toyota"),
    model: String::from("Camry"),
    ..Default::default()
};

在上面的示例中,我们使用了Default trait 中的 default 方法来初始化剩余的成员变量为默认值。

3.3 使用示例:实例化一个结构体并初始化

struct Person {
    name: String,
    age: u32,
    city: String,
}

impl Person {
    fn new(name: String, age: u32, city: String) -> Person {
        Person {
            name,
            age,
            city,
        }
    }
}
fn main() {
    let person1 = Person::new(String::from("Alice"), 25, String::from("New York"));
    let person2 = Person {
        name: String::from("Bob"),
        ..person1
    };

    println!("Person 1: {}, {}, {}", person1.name, person1.age, person1.city);
    println!("Person 2: {}, {}, {}", person2.name, person2.age, person2.city);
}

在上述示例中,我们定义了一个名为Person的结构体,它有三个成员变量:name、age和city。我们为Person结构体实现了一个关联函数new,用于创建实例并初始化其成员变量。

在main函数中,我们使用Person::new关联函数创建了一个名为person1的Person结构体实例。然后,我们使用结构体初始化语法通过person1的值来初始化person2,其中只指定了name字段,其他字段使用person1的对应值。

通过结构体的实例化和初始化,我们可以根据需要创建具有不同属性的结构体实例,并灵活地操作和访问其成员变量。这为我们提供了更多控制和定制化的能力。

4. 结构体的实现

4.1 为结构体实现方法

在Rust中,我们可以为结构体实现方法,使得结构体实例能够执行特定的行为。

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn is_square(&self) -> bool {
        self.width == self.height
    }
}

上述代码定义了一个名为Rectangle的结构体,并为其实现了两个方法:area和is_square。area方法计算矩形的面积,is_square方法判断矩形是否为正方形。

let rect = Rectangle {
    width: 10,
    height: 20,
};

println!("Area: {}", rect.area());
println!("Is Square: {}", rect.is_square());

在上面的示例中,我们创建了一个名为rect的Rectangle结构体实例,并通过调用area和is_square方法来获取矩形的面积和判断是否为正方形。

通过为结构体实现方法,我们可以将特定的行为与结构体关联起来,使得结构体实例能够直接调用方法来执行相应的操作。

4.2 为结构体实现 trait

除了可以为结构体实现自定义的方法外,我们还可以为结构体实现特定的 trait,从而赋予结构体更多的功能和行为。

struct Circle {
    radius: f64,
}

trait Shape {
    fn area(&self) -> f64;
}

impl Shape for Circle {
    fn area(&self) -> f64 {
        3.14 * self.radius * self.radius
    }
}

上述代码定义了一个名为Circle的结构体,并为其实现了Shape trait。Shape trait 包含一个area方法,用于计算形状的面积。

let circle = Circle { radius: 5.0 };

println!("Area: {}", circle.area());

在上面的示例中,我们创建了一个名为circle的Circle结构体实例,并通过调用area方法来获取圆形的面积。

通过为结构体实现 trait,我们可以将特定的行为和功能抽象出来,并将其应用于不同的结构体上。这样可以实现代码的重用和更好的模块化。

4.3 示例:为结构体实现方法和 trait

struct Square {
    side_length: u32,
}

trait Shape {
    fn area(&self) -> u32;
    fn perimeter(&self) -> u32;
}

impl Shape for Square {
    fn area(&self) -> u32 {
        self.side_length * self.side_length
    }

    fn perimeter(&self) -> u32 {
        4 * self.side_length
    }
}

impl Square {
    fn is_square(&self) -> bool {
        self.side_length > 0 && self.side_length == self.perimeter() / 4
    }
}
fn main() {
    let square = Square { side_length: 5 };

    println!("Area: {}", square.area());
    println!("Perimeter: {}", square.perimeter());
    println!("Is Square: {}", square.is_square());
}

在上述示例中,我们定义了一个名为Square的结构体,并为其实现了Shape trait 和 is_square 方法。Shape trait 包含了计算面积和周长的方法。

在main函数中,我们创建了一个名为square的Square结构体实例,并通过调用area、perimeter和is_square方法来获取正方形的面积、周长以及判断是否为正方形。

通过结构体的方法和 trait 的实现,我们可以扩展结构体的功能,使其具备更多的行为和特性,同时也提高了代码的可读性和可维护性。

5. 结构体与面向对象

5.1 面向对象的特点:抽象、封装、继承、多态

面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,具有以下特点:

  • 抽象(Abstraction):通过将现实世界的对象抽象成类和对象的概念,从而将复杂的问题简化为更易于理解和处理的模块。
  • 封装(Encapsulation):将数据和操作封装在对象中,对象对外部隐藏了内部实现细节,只提供有限的接口与外界进行交互。
  • 继承(Inheritance):通过定义父类和子类之间的关系,子类可以继承父类的属性和方法,从而实现代码的重用和扩展。
  • 多态(Polymorphism):同一种操作可以根据不同对象的类型执行不同的行为,提高代码的灵活性和可扩展性。

5.2 结构体的继承

在Rust中,没有直接的结构体继承机制,但可以通过其他方式实现类似的功能。

5.2.1 tuple 结构体

Tuple 结构体可以被看作是一组没有具名字段的结构体,可以用于表示一组相关的值。

struct Person(String, u32);

fn main() {
    let person = Person(String::from("Alice"), 25);

    println!("Name: {}", person.0);
    println!("Age: {}", person.1);
}

在上述示例中,我们定义了一个名为Person的 tuple 结构体,它包含了一个字符串类型和一个无符号32位整数类型。通过索引访问元组的元素,可以获得相应的值。

5.2.2 结构体的嵌套

结构体可以相互嵌套,形成层级关系,从而实现类似继承的效果。

struct Person {
    name: String,
    age: u32,
}

struct Employee {
    person: Person,
    employee_id: u32,
}

fn main() {
    let person = Person {
        name: String::from("Alice"),
        age: 25,
    };

    let employee = Employee {
        person,
        employee_id: 12345,
    };

    println!("Name: {}", employee.person.name);
    println!("Age: {}", employee.person.age);
    println!("Employee ID: {}", employee.employee_id);
}

在上面的示例中,我们定义了一个名为Person的结构体和一个名为Employee的结构体。Employee结构体包含了一个Person类型的成员变量person,以及一个employee_id成员变量。

通过结构体的嵌套,我们可以在一个结构体中包含另一个结构体,从而实现类似继承的关系,使得代码更加结构化和模块化。

5.2.3 实战示例:结构体的继承和嵌套

struct Shape {
    color: String,
}

struct Rectangle {
    shape: Shape,
    width: u32,
    height: u32,
}

struct Circle {
    shape: Shape,
    radius: f64,
}

fn main() {
    let red_rectangle = Rectangle {
        shape: Shape {
            color: String::from("red"),
        },
        width: 10,
        height: 20,
    };

    let blue_circle = Circle {
        shape: Shape {
            color: String::from("blue"),
        },
        radius: 5.0,
    };

    println!("Rectangle: {} x {}", red_rectangle.width, red_rectangle.height);
    println!("Circle: radius {}", blue_circle.radius);
    println!("Color: Rectangle - {}, Circle - {}", red_rectangle.shape.color, blue_circle.shape.color);
}

在上述示例中,我们定义了一个名为Shape的结构体,以及两个派生结构体Rectangle和Circle。Rectangle和Circle结构体分别嵌套了Shape结构体,从而实现了继承和代码复用的效果。

通过使用结构体的继承和嵌套,我们可以在Rust中模拟实现面向对象编程的特性,使得代码更加灵活和可扩展。

5.3 使用结构体描述对象

结构体可以被用来描述和表示现实世界中的对象,它们可以具有属性(字段)和行为(方法)。

struct Person {
    name: String,
    age: u32,
}

impl Person {
    fn introduce(&self) {
        println!("My name is {} and I am {} years old.", self.name, self.age);
    }
}
fn main() {
    let person = Person {
        name: String::from("Alice"),
        age: 25,
    };

    person.introduce();
}

在上面的示例中,我们定义了一个名为Person的结构体,它具有name和age两个字段。通过为Person结构体实现introduce方法,我们可以在对象上调用该方法来介绍自己。

在main函数中,我们创建了一个名为person的Person结构体实例,并通过调用introduce方法来打印自我介绍。

通过使用结构体来描述对象,我们可以将对象的属性和行为封装在一起,实现数据和操作的高度内聚性,使得代码更加清晰和可维护。

5.4 与基于类描述对象的对比

Rust中的结构体和面向对象编程中的类有些相似,但也有一些不同之处。本章接下来将从以下几个方面与以 Java 为代表的典型基于类的面向对象编程语言进行对比:

  • 封装性
  • 继承性
  • 多态性
  • 所有权系统

5.4.1 封装性

Rust中的结构体可以使用pub关键字来控制字段和方法的可见性,实现封装。而面向对象的类默认具有公共接口,可以被外部访问。

Rust 语言 面向对象语言如Java
Rust中的结构体可以使用 pub 关键字来控制字段和方法的可见性,从而实现封装。默认情况下,结构体的字段和方法是私有的,只能在同一模块内访问。 面向对象语言如Java:面向对象语言通常使用访问修饰符(如 public、private)来控制类的成员的可见性。类的成员可以被其他类或对象访问。

5.4.2 继承性

Rust中的结构体没有直接的继承机制,但可以通过结构体的嵌套和 trait 的实现来达到类似的效果。

Rust 语言 面向对象语言如Java
Rust中的结构体没有直接的继承机制。然而,可以通过结构体的嵌套和 trait 的实现来实现类似的功能。通过嵌套结构体,可以创建一个结构体,其中包含其他结构体作为其字段。 面向对象语言中的继承允许一个类派生出另一个类,从而实现代码的复用。子类继承了父类的属性和方法,并且可以添加或重写这些成员。

5.4.3 多态性

Rust通过 trait 和泛型来实现多态性,不同类型的结构体可以实现相同的 trait,并以相同的方式进行处理。

Rust 语言 面向对象语言如Java
Rust通过 trait 和泛型来实现多态性。不同类型的结构体可以实现相同的 trait,并以相同的方式进行处理。这使得代码更具灵活性,能够处理不同类型的对象。 面向对象语言使用继承和接口来实现多态性。子类可以替代父类的位置,并以多态的方式使用。

5.4.4 所有权系统

Rust的所有权系统使得在处理对象时更加安全和高效,避免了一些内存管理的问题。

Rust 语言 面向对象语言如Java
Rust的所有权系统确保了内存安全和资源管理。结构体在Rust中是拥有所有权的,当结构体被销毁时,它们的资源也被释放。这种所有权系统使得在处理对象时更加安全和高效。 面向对象语言通常使用垃圾回收或手动内存管理来管理对象的生命周期和内存使用。

6. 总结

本文中我们深入探讨了Rust中的结构体(struct)的概念、用法和实际应用。我们首先介绍了结构体的基本定义和使用,包括如何声明结构体、定义字段和方法,并通过示例代码展示了结构体的基本操作。接着,我们详细讨论了结构体中的成员,包括成员变量和成员方法。我们介绍了如何在结构体中定义字段和方法,并通过示例演示了如何使用结构体的成员进行操作和访问。然后,我们讨论了结构体的实例化,包括创建结构体实例和结构体实例的初始化。我们介绍了通过new函数和简化的初始化语法来创建结构体实例,并通过示例代码展示了不同的实例化方式。

接下来,我们探讨了结构体的实现,包括为结构体实现方法和 trait。我们详细介绍了如何为结构体定义方法,并通过示例代码展示了方法的使用。同时,我们讨论了如何为结构体实现 trait,以扩展结构体的功能和行为。最后,我们与面向对象编程进行了比较,讨论了结构体与面向对象的特点和区别。我们介绍了结构体的继承和嵌套的实现方式,并通过示例代码展示了如何在Rust中模拟实现面向对象的特性。

你可能感兴趣的:(Rust学习笔记,rust,开发语言,结构体,面向对象)