7.3.结构体-方法

方法和函数类似,但是方法必须归属到某个结构体、枚举或者trait对象内,而函数则不必。方法的一个参数总是self,他表示被调用的这个结构的方法本身的实例。

      1. 定义方法的语法

结构体方法定义的函数的语法如下所示:

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!("长方形的面积是:{}", rect.area());

}

定义结构体的函数,必须在结构体前面以impl这个关键字开始,后面跟着结构体的名称,在然后使用花括号包含需要实现的功能的代码。在主函数中调用rect的area方法。rect是结构体Rectangle结构体的实例,使用小数点"."分割,后面跟着方法名、小括号和一些参数。参数"&self"是self: &Self的简写形式,它表示的是rectangle:&Rectangle的替代品。它是impl要实现的结构体本身。符号"&"表示借用所用权,因此它所指的变量是不可变的。在这个方法使用借用,表示它不会取得所有权,只需要读取机构体中的属性值。如果需要修改属性值,则需要使用可变借用使用符号"&mut self"。一般很少使用self直接获取所有权,但是如果需要将self转换为其他某些东西,且需要在转换后组织调用者访问原有的实例,一般可以直接用self。

使用方法而不是函数的主要作用是将相关功能组合在一起,而不是在不同的库中进行查找。

注意,我们可以使用和属性名称相同的方法名称,例如下面使用相同的width作为方法名。

rust 复制代码
#[derive(Debug)]

struct Rectangle {

    width: u32,

    height: u32,

}

impl Rectangle {

    fn width(&self) -> bool {

        self.width > 0

    }

}

fn main() {

    let rect = Rectangle {

        width: 30,

        height: 50,

    };

    println!("长方形的宽度是否大于零:{}", rect.width());

}

width后面跟着小括号则表示是方法,如果后面没有小括号则表示为属性。当时当使用相同名称的方法时,通常会返回该属性值,这样的方法通常叫做getter,Rust不会像其他语言一样会自动实现这样的功能。

      1. 操作符"->"到哪去了?

在C或C++语言中,有两种不同的操作符可以调用的它的方法,如果object是一个指针,则调用方法的语法为:object->something(),或者使用(*object).something()。

Rust语言没有"->"操作符;但是它有一个称之为自动引用和解引用的特性。调用方法是使用该特性为数不多的几种场景之一。这个特性会自动将符号"&"、"&mut"或"*"到object之前,以便它符合方法的签名,换而言之,下面的两行代码是相同的。

p1.distance(&p2);

(&p1).distance(&p2);

第一条看上去更加清晰,因为方法有一个更加清晰的接收者,self类型,因此自动引用行为就起作用了。指定了接收者方法名,Rust就可以明确到底是使用借用、可变借用还是所有权转移。这大大符合了人类的使用习惯。

      1. 有更多参数的方法

下面我们增加一个方法can_hold,它有第二参数,它是Rectangle的借用类型,它和自己的宽和高进行比较,如果都是大于,则返回ture,否则返回false。代码如下所示:

rust 复制代码
#[derive(Debug)]

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: 36,

        height: 50,

    };

    let rect3 = Rectangle {

        width: 10,

        height: 20,

    };

    println!("rect1是否大于rect2:{}", rect1.can_hold(&rect2));

    println!("rect1是否大于rect3:{}", rect1.can_hold(&rect3));

}

程序运行结果为:

rust 复制代码
rect1是否大于rect2:false

rect1是否大于rect3:true
      1. 关联函数

所有在impl块中定义的函数都叫做关联函数,因为它和结构体本身是有相关性的。关联函数的参数不会将slef作为第一个参数,因为它不需要使用到结构体本身。例如:定义在Sting类型中的String::from函数。

关联函数不是方法,它通常用作构造器,返回结构体本身的一个实例。通常这些构造器叫做new,new并不是一个特殊的名字,并没有内置于语言中。

下面的示例中有个关联函数square,它会创建宽和高相同的一个正方形,因为宽和高相同,只需要一个参数就可以了。

rust 复制代码
#[derive(Debug)]

struct Rectangle {

    width: u32,

    height: u32,

}

impl Rectangle {

    fn square(length: u32)->Self{

        Self {

            width: length,

            height: length,

        }

    }

}

fn main() {

    let rect1 = Rectangle::square(10);

   

    println!("rect1{:#?}", rect1);

}
      1. 多个impl块

结构体运行有多个impl块,它是一种有效的语法,可能是为了不修改之前版本的代码,而使用功能的迭代。

rust 复制代码
#[derive(Debug)]

struct Rectangle {

    width: u32,

    height: u32,

}

impl Rectangle {

    fn square(length: u32) -> Self {

        Self {

            width: length,

            height: length,

        }

    }

}

impl Rectangle {

    fn area(&self)->u32 {

        self.width * self.height

    }

}

fn main() {

    let rect1 = Rectangle::square(10);


    println!("rect1{:#?}", rect1);

    println!("正方体的面积是:{:?}", rect1.area());

}

结构体可以创建你自己的类型,这对于你的工作领域是特别有意义的。通过使用结构体,你可以将相互关联的数据相互组合在一起,使你的代码更加清晰。在impl块中,你可以定义和你类型有关的函数、方法(结构体实例本身应该具备的一些行为)。

相关推荐
chenbin___2 小时前
检查hooks依赖的工具(转自千问)
开发语言·前端·javascript·react native·react.js
掘金者阿豪2 小时前
一个权限配置错误引发的“血案”:数据库访问控制手记
后端
消失的旧时光-19432 小时前
Spring Boot 接口设计进阶:POST / PUT / DELETE 的本质区别与工程实践
spring boot·后端
久爱@勿忘2 小时前
vue/uniapp H5页面截图
开发语言·前端·javascript
2301_800976932 小时前
python的协程
开发语言·python
StackNoOverflow2 小时前
Spring Cloud的注册中心和配置中心(Nacos)
后端·spring cloud
武超杰2 小时前
Spring Cloud Alibaba Nacos 进阶:配置隔离、集群、持久化与开机自启
java·开发语言
Rabitebla2 小时前
C++类和对象(中):默认函数 + 运算符重载 + 日期类实现完整笔记
java·开发语言·javascript
Bat U2 小时前
JavaEE|多线程(一)
java·服务器·开发语言