Rust能力养成之(5):功能与方法

图片

前言

上一篇,介绍了Rust语言的

  • 结构体

  • 枚举

如果类型(Types)只有属性,没有动态行为,显然是不够的,在实际场景中,我们需要与类型有些互动,比如利用函数(function)或方法(method)得到返回值,或者可以对已有属性进行操作或修改。

Rust为我们准备了 impl blocks,字面看来,就是为类型实现(implementations)点什么,其同时适用于用户自定义任何封装类型

那么,这一篇,我们介绍的函数和方法实现涉及

  • 结构体的函数和方法实现

  • 枚举的函数和方法实现

  • 模块简介

结构体之功能实现

这里的代码为之前写过的Player 结构添加两个功能:

  • 第9行:记住impl这个关键字

  • 第10-16行:一个类似于构造函数的函数(dong xi),接受名称并为Person中的其余字段设置默认值

  • 第18-24行:两个方法函数,get_friends和set_friends,分别负责取名和取数

// struct_methods.rs
struct Player {
   
       name: String,    iq: u8,    friends: u8}
impl Player {
   
       fn with_name(name: &str) -> Player {
   
           Player {
   
               name: name.to_string(),            iq: 100,            friends: 100        }    }
    fn get_friends(&self) -> u8 {
   
           self.friends    }
    fn set_friends(&mut self, count: u8) {
   
           self.friends = count;    }}
fn main() {
   
       let mut player = Player::with_name("Dave");    player.set_friends(23);    println!("{}'s friends count: {}", player.name, player.get_friends());    // another way to call instance methods.    let _ = Player::get_friends(&player);}

代码结果为:

图片

在写实现的时候,通常会有两种方法(methods)可写:

  • Associated methods:这种方法,不需要self 类型作为第一参数,上面示例中的with_name 方法就是这种,类似于面向对象编程中的静态方法(static method),可以认为这种方法是自身具足的,参见第28行

  • Instance methods:该方法以self为第一参数,与Python类似,因此只能借由实例(instance)唤起,参见第29行,而第32行提供了另一种调用该类方法的方式(读者可以自己试一下,如果不用指针类型作为参数,会出现什么情况?)

再看一下 set_friends方法是参数 &mut self,表明self是在运行时从类型实例中借用过来的,如果不用&,则会把实例的值赋给该方法,等运行之后,又会重新释放。

读到这里,好像有点不知所云,请读者记住这一点,很快就会在内存管理与安全的部分给大家一个交代。

枚举之功能实现

这里进入枚举部分,看一个有关支付的代码示例,​​​​​​​

// enum_methods.rs
enum PaymentMode {
   
       Debit,    Credit,    Paypal}
// Bunch of dummy payment handlers
fn pay_by_credit(amt: u64) {
   
       println!("Processing credit payment of {}", amt);}fn pay_by_debit(amt: u64) {
   
       println!("Processing debit payment of {}", amt);}fn paypal_redirect(amt: u64) {
   
       println!("Redirecting to paypal for amount: {}", amt);}
impl PaymentMode {
   
       fn pay(&self, amount: u64) {
   
           match self {
   
               PaymentMode::Debit => pay_by_debit(amount),            PaymentMode::Credit => pay_by_credit(amount),            PaymentMode::Paypal => paypal_redirect(amount)        }    }}
fn get_saved_payment_mode() -> PaymentMode {
   
       PaymentMode::Debit}
fn main() {
   
       let payment_mode = get_saved_payment_mode();    payment_mode.pay(512);}

代码结果如下

图片

以上代码非常明朗,这里的实现方法名称为:get_saved_payment_mode()用来返回用户的付款模式:Credit Card, Debit Card, or Paypal显然很适合用枚举建模,这3种模式显然作为枚举变体。

在pay方法中,用户可以任选三种付款方式之一进行支付,该方法对应决定使用哪一种,而后进行指派。请读者最后自己按照具体场景,敲一下这个代码,相信会感到这里面枚举所起到的作用是非常有恰当的。

进一步说来,枚举广泛用于状态机建模,当与match语句结合使用时,可以使状态转换代码编写起来非常简洁;还可以用于自定义错误类型方面的建模。

当enum变量没有与之关联的任何数据时,可以像C枚举那样使用,其中的变量隐式的具有从0开始的整数值,但也可以手动标记为整数值(isize),而这在与外部C库交互时还是很有用的。

模块(modules)简介

任何编程语言都会提供一种方法,将相对繁重的代码拆分为多个文件,以管理复杂性,Rust使用模块来做这件事,有关模块的详细介绍,会放在本系列的第二部分。这里列出一些重点,作为本部分后续章节的基础。

  • 每个Rust程序都需要有一个root模块。在可执行文件中,通常是main.rs,对于libraries,是libraries .rs

  • 模块可以在其他模块中声明,也可以作为文件和目录

  • root模块要使用mod关键字来声明,以保证编译器可以识别

  • 要使用模块内的任何项目,需要使用use关键字以及模块的名称来引用

  • 模块中定义的项目默认情况下是私有的,需要使用pub关键字将其公开

结语

可以看出,本篇与上一篇形成一一对应,上一篇重点在于如何定义结构体和枚举的属性,本篇介绍了如何与这两种用户自定义类型进行互动,并对之进行操作,而使这些代码编写变得灵活,表现力充分增强,效果自然可期。难怪某位Rust中文社区的一位资深成员谈及:这么多年了,Rust让我又感到了编程的乐趣。

下一篇,我们看下集合体与迭代器

主要参考和建议读者进一步阅读的文献

https://doc.rust-lang.org/book

1.Rust编程之道,2019, 张汉东

2.The Complete Rust Programming Reference Guide,2019, Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger

3.Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger

4.Beginning Rust ,2018,Carlo Milanesi

5.Rust Cookbook,2017,Vigneshwer Dhinakaran

猜你喜欢

转载自blog.csdn.net/qq_40433634/article/details/112625890