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块中,你可以定义和你类型有关的函数、方法(结构体实例本身应该具备的一些行为)。

相关推荐
Csvn2 分钟前
日志分析进阶 — Logwatch 与 GoAccess 实战
后端
Moment3 分钟前
牛逼,NextJs 从 16.3 开始全面拥抱 Agent Native 🥰🥰🥰
前端·后端·面试
Csvn21 分钟前
CI/CD 入门 — 用 GitLab CI 构建自动化部署流水线
后端
沸点小助手24 分钟前
6月沸点活动获奖名单公示|本周互动话题上新🎊
前端·后端
远航_36 分钟前
git submodule
前端·后端·github
狂师43 分钟前
测试工程师的AI 技能库:推荐5个让你效率翻倍的Skills
前端·后端·测试
CodeSheep1 小时前
DeepSeek正式官宣摇人,夯!
前端·后端·程序员
doiito1 小时前
【Agent Harness】Gliding Horse 设计细节 -- 不跟风开发自己的AI Agent
架构·rust·agent
亦暖筑序1 小时前
Java 8老系统AI Workflow实战:把一次性AI对话升级成可恢复工作流
java·后端
血小溅1 小时前
飞书 CLI 集成基础教程
后端