Rust能力养成系列之(2):功能抽象

图片

前言

上一篇,介绍了Rust语言的

  • 安装与编译

  • 基本数据类型

  • 变量声明和不可变绑定

这其中已经蕴含着Rust精华的成分了。

本篇内容将涉及

  • 常规函数

  • 闭包

  • 字符串

函数(Function)

一般而言,编程语言中的函数,将过程性指令抽象为专名的功能实体,以重复调用,简化代码。

在上一篇中,我们已经看过了main函数,这里看下如何定义一个常规函数

//function.rsfn add(a: u64, b: u64) -> u64 {
   
       a + b}fn main() {
   
       let a: u64 = 17;    let b = 3;    let result = add(a, b);    println!("Result {}", result);}

解释代码

从以上代码第2行可见,

  • 这个add 是一个简单的加法函数,

  • fn是创建函数的关键字,

  • 参数 a,b在函数名的括号中,各自的数据类型显式的声明在冒号之后,

  • 返回类型也得到显式声明->u64, 如果没有返回值,这一步可以不写

  • 如第一篇所提及,函数是有类型的,这里为 fn(u64, u64) -> u64

    • 显然,函数也可以作为变量和其他函数的参数

第3行

  • 现已不需要return关键词进行函数值返回

再看一下main函数,第5-10行:

  • 第6行,声明了一个变量a,及其类型,并初始化

  • 第7,8行,声明变量b,result,并初始化,

    • 这里没有显式声明b的类型,表明是可以省略的,因为Rust能够在大多数情况对代码中的变量类型进行正确推断,不难得知:b和result 都是u64

对类型的显式声明在Rust中是有其目的:

  • 避免类型标识上可能出现的冲突

  • 提升代码的可读性,尤其当多种类型嵌套一起时

Rust的类型推理基于Hindly Milner类型系统,是一整套支持编程语言中类型推断的规则和算法,可在线性时间内执行,不但高效,而且在大型程序的类型检查中很为实用。

上述代码结果

图片

我们再看一个改变函数参数的代码实例。

// function_mut.rsfn increase_by(mut val: u32, how_much: u32) {
   
       val += how_much;    println!("You made {} points", val);}fn main() {
   
       let score = 2048;    increase_by(score, 30);}

解释代码

代码不长,大致说下:在main函数中,声明score,初始化为2048;调用increase_by函数,30为该函数的第2个参数。需要说明一下,在increas_by中,明确了第1个参数为mut val,表明这一参数可以在该函数内部改变赋值,这显然是可变绑定在函数体中的一次体现。

上述代码结果

图片

闭包(Closure)

到这里,谈一下Rust中也同样支持的闭包,

  • 其与函数相似,但在声明之时,附及更多的环境(environment)或范围(scope)信息;

  • 再者,定义时,函数有名(关键字fn),而闭包无名,虽然无名,但又能够赋值

  • 同函数一样,可以作为值存储,并被其他的函数体调用。

  • 闭包的主体,可以单行,也可以多行

举例而言,一个简单的闭包可能形如:let my_closure = || ();  ,可见这个闭包既无参数,又没有任何功能,可以直接调用my_closure(),;而||是用来装载参数的,比如|a,b|, 如果感到类型不太好推断,当然最好明确类型,如|a:u32|。

我们看一下这个代码,里面有两个闭包doubler 和big_closure

// closures.rsfn main() {
   
       let doubler = |x| x * 2;    let value = 5;    let twice = doubler(value);    println!("{} doubled is {}", value, twice);
    let big_closure = |b, c| {
   
           let z = b + c;        z * twice    };
    let some_number = big_closure(1, 2);    println!("Result from closure: {}", some_number);}

可见:

  • 第3行,一定不要看成是绝对值,这是一个单行闭包--doubler,参数是x,功能是返回x的2倍;

  • 第4行,初始化变量value=5

  • 第5行,初始化变量twice=doubler(value),同时也是调用闭包doubler

  • 第6行,打印相关值

  • 第8-11,第2个闭包big_closure ,是一个多行闭包,参数为b,c;函数内定义初始化变量z,最终返回z*twice的值

  • 第13行,初始化变量some_number,调用闭包big_closure

  • 第14行,打印相关值

上述代码结果

图片

有关闭包的用途,主要是作为高阶函数(higher-order function)的参数,原因在于闭包可以提供相对便利的抽象(convenient abstraction)。

相关的实例,比如:thread::spawn或者迭代器Iterator特性中的filter方法,但这些东西,在本文中尚非重点,而且需要很多前提知识才能讲清楚,会在后续有关Rust高级概念的篇章中详细介绍。

 

字符串(String)

字符串是编程语言中颇为常用的数据类型,在Rust中,通常有两种形式:

  • 字符串,String

  • 字符串指针,&str,与C语言一样,&就是一个指针符号

Rust字符串是有效的UTF-8编码的字节序列;像C字符串那样以null结尾,之间可以包含null字节。

我们看一下代码实例

// strings.rsfn main() {
   
       let question = "How are you ?";            // a &str type    let person: String = "Bob".to_string();    let namaste = String::from("नमस्ते");        // unicodes yay!
    println!("{}! {} {}", namaste, question, person);}

依然是不难的代码,希望我们这可以这样循序渐进的学下去。

  • 第1行,初始化一个字符串指针&str类型的变量question

  • 第2-3行,初始化String类型变量person 和namaste

上述代码结果

图片

显然存在多种方式创建String类型。字符串变量分配在(heap)上,而字符串指针类型&str,指向一个现有字符串,既可以在堆,也可在(stack)上。

这里依然还是一个简单介绍,关于字符串的进一步讨论会在之后篇章中继续。

结语

本文介绍了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 

4.Rust,2018,Claus Matzinger

5.Beginning Rust ,2018,Carlo Milanesi

6.Rust Cookbook,2017,Vigneshwer Dhinakaran

猜你喜欢

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