当前位置: 首页 > article >正文

【Rust练习】16.方法和关联函数

练习题来自:https://practice-zh.course.rs/method.html

1 🌟🌟 方法跟函数类似:都是使用 fn 声明,有参数和返回值。但是与函数不同的是,方法定义在结构体的上下文中(枚举、特征对象也可以定义方法),而且方法的第一个参数一定是 self 或其变体 &self 、&mut self,self 代表了当前调用的结构体实例。

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

impl Rectangle {
    // 完成 area 方法,返回矩形 Rectangle 的面积
    fn area
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };

    assert_eq!(rect1.area(), 1500);
}

答案如下

impl Rectangle {
    // 完成 area 方法,返回矩形 Rectangle 的面积
    fn area(&self) -> u32{
        self.width * self.height
    }
}

说几个我觉得和C++的类成员函数的区别:

  1. 关联方法类似C++的静态方法(static),而方法就是类成员函数了,调用规则和C++是一样的。
  2. self引用类似C++的this指针,但是rust的self引用是强制的,必须写在参数列表里,且访问成员时必须加入self限定;而C++的this指针不是强制的,参数不能写this指针,访问成员也不强制加限定(除非冲突)
  3. 因为第二条,显然Rust的关联方法是不能访问成员变量的,C++的静态方法可以访问静态成员变量。

2 🌟🌟 self 会拿走当前结构体实例(调用对象)的所有权,而 &self 却只会借用一个不可变引用,&mut self 会借用一个可变引用

// 只填空,不要删除任何代码行!
#[derive(Debug)]
struct TrafficLight {
    color: String,
}

impl TrafficLight {
    pub fn show_state(__)  {
        println!("the current state is {}", __.color);
    }
}
fn main() {
    let light = TrafficLight{
        color: "red".to_owned(),
    };
    // 不要拿走 `light` 的所有权
    light.show_state();
    // 否则下面代码会报错
    println!("{:?}", light);
}

答案

impl TrafficLight {
    pub fn show_state(&self)  {
        println!("the current state is {}", self.color);
    }
}

所有权转移大多用来销毁某些资源,这和C++的析构函数有异曲同工之妙。

3 🌟🌟 &self 实际上是 self: &Self 的缩写或者说语法糖

struct TrafficLight {
    color: String,
}

impl TrafficLight {
    // 使用 `Self` 填空
    pub fn show_state(__)  {
        println!("the current state is {}", self.color);
    }

    // 填空,不要使用 `Self` 或其变体
    pub fn change_state(__) {
        self.color = "green".to_string()
    }
}
fn main() {}

self是引用本身,Self其实就是本身类型的别名

impl TrafficLight {
    // 使用 `Self` 填空
    pub fn show_state(self: &Self)  {
        println!("the current state is {}", self.color);
    }

    // 填空,不要使用 `Self` 或其变体
    pub fn change_state(&mut self) {
        self.color = "green".to_string()
    }
}

4 🌟🌟 定义在 impl 语句块中的函数被称为关联函数,因为它们跟当前类型关联在一起。关联函数与方法最大的区别就是它第一个参数不是 self ,原因是它们不需要使用当前的实例,因此关联函数往往可以用于构造函数:初始化一个实例对象。

#[derive(Debug)]
struct TrafficLight {
    color: String,
}

impl TrafficLight {
    // 1. 实现下面的关联函数 `new`,
    // 2. 该函数返回一个 TrafficLight 实例,包含 `color` "red"
    // 3. 该函数必须使用 `Self` 作为类型,不能在签名或者函数体中使用 `TrafficLight`
    pub fn new() 

    pub fn get_state(&self) -> &str {
        &self.color
    }
}

fn main() {
    let light = TrafficLight::new();
    assert_eq!(light.get_state(), "red");
}

基本的一个构造函数,不过C++的构造函数往往是和类同名的,new关键字一般用于在堆上分配内存。

impl TrafficLight {
    pub fn new(colour: String) -> Self{
        TrafficLight{color: colour}
    } 

    pub fn get_state(&self) -> &str {
        &self.color
    }
}

5 🌟 每一个结构体允许拥有多个 impl 语句块


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

// 使用多个 `impl` 语句块重写下面的代码
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}


fn main() {}

其实我一直很好奇,Rust这种组织方式,项目的结构会不会很难看。

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

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

6 🌟🌟🌟 我们还可以为枚举类型定义方法


#[derive(Debug)]
enum TrafficLightColor {
    Red,
    Yellow,
    Green,
}

// 为 TrafficLightColor 实现所需的方法
impl TrafficLightColor {
    
}

fn main() {
    let c = TrafficLightColor::Yellow;

    assert_eq!(c.color(), "yellow");

    println!("{:?}",c);
}

需要针对self的值进行匹配,并返回对应的&str,这里给出一种简单的实现:

impl TrafficLightColor {
    fn color(&self) -> &str{
        match self {
            TrafficLightColor::Yellow => "yellow",
            _ => "default"
        }
    }
}

http://www.kler.cn/a/326876.html

相关文章:

  • 103 - Lecture 1
  • 【LuatOS】基于WebSocket的同步请求框架
  • Git 概述及相关命令(1)
  • 【系统架构设计师】2023年真题论文: 论面向对象分析的应用与实现(包括解题思路和素材)
  • 智能网联汽车:人工智能与汽车行业的深度融合
  • java、excel表格合并、指定单元格查找、合并文件夹
  • helm部署ingress-nginx
  • Docker-2.如何保存数据退出
  • 什么是文件完整性监控(FIM)
  • ComfyUI新版本快捷键大全,快速提升效率,建议收藏
  • CMake教程(八):添加定制命令和生成的文件
  • 如何使用ssm实现白云会议管理系统+vue
  • mysql学习教程,从入门到精通,SQL 修改表(ALTER TABLE 语句)(29)
  • AI驱动TDSQL-C Serverless 数据库技术实战营-与AI的碰撞
  • Android 属性contentDescription详解
  • 斩获亚马逊“商采转型之星”奖 ,益而益(ELEGRP)品牌出海正当时
  • fatfs API使用手册
  • 《深度学习》卷积神经网络CNN 实现手写数字识别
  • 【C++打怪之路Lv4】-- 类和对象(中)
  • 方法 WebDriverWait
  • Java应用文件上传超出默认大小
  • 【888题竞赛篇】第十二题,2024ICPC网络赛第二场-游戏(Game)
  • 【容器云】容器云设计方案
  • Linux编译部署PHP环境
  • 冒泡排序-C语言
  • 程序员如何提升核心竞争力——深度耕耘与软技能的培养》