Rust语言圣经06 - 不仅仅是Hello world

Posted 编程学院

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rust语言圣经06 - 不仅仅是Hello world相关的知识,希望对你有一定的参考价值。

原文链接:https://course.rs/first-try/hello-world.html
 
欢迎大家加入Rust编程学院,中国最好的Rust学习社区

  1. 官网:https://college.rs
  2. QQ群:1009730433

不仅仅是Hello world

几乎所有教程中安装的最后一个环节都是hello world,我们也不能免俗,但是在hello world之后,还有一个相亲,阿呸,Rust初印象环节,希望大家喜欢。

多国语言的"世界,你好"

还记得我们之前讲到的VScode IDE和通过Cargo创建的世界,你好工程吧?

现在使用VScode打开我们在上一节中创建的world_hello工程, 然后打开main.rs文件,这是当前Rust工程的入口文件,和其它语言没有区别。

将该文件内容修改为:

fn greet_world() 
     let southern_germany = "Grüß Gott!";
     let chinese = "世界,你好";
     let english = "World, hello";
     let regions = [southern_germany, chinese, english];
     for region in regions.iter() 
             println!("", &region);
     
 
 
 fn main() 
     greet_world();
 

然后打开终端,进入world_hello工程根目录,运行该程序(你也可以在VScode中打开终端,方法是点击左下角的错误和警告图标),可以看到来自世界各地的热情招呼:

$ cargo run
   Compiling world_hello v0.1.0 (/Users/sunfei/development/rust/world_hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
     Running `target/debug/world_hello`
Grüß Gott!
世界,你好
World, hello
sunfei@sunfeideMa

花点时间来看看上面的代码,首先,Rust原生支持UTF-8编码的字符串,这意味着你可以很容易的使用其它语言作为字符串内容。

其次,关注下println后面的!,如果你有Ruby编程经验,那么你可能会认为这是解构操作符,但是在Rust中,这是操作符,你目前可以认为宏是一种特殊类型函数。对于println来说,我们没有使用其它语言惯用的%s,%d来做输出占位符,而是使用,因为Rust在底层帮我们做了大量工作,会自动识别输出数据的类型,例如当前例子,会识别为string类型。

最后,和其它语言不同,rust的集合类型不能直接进行循环,需要变成迭代器(这里是通过.iter()方法)后,才能用于迭代循环,在目前来看,你会觉得这一点好像挺麻烦,不急,以后就知道这么做的好处所在.

至于函数声明、调用、数组的使用,和其它语言没什么区别,so easy!

Rust语言初印象

Rust这门语言对于Haskell和Java开发来说,会觉得很熟悉,因为它们在高阶表达方面都很优秀,简而言之,可以很简洁的写出原本需要一大堆代码才能表达的含义,但是Rust又有所不同:它的性能是底层语言级别的性能,可以跟C/C++相媲美。

在上一节,咱们学习了非常简单的Rust入门代码,现在来点复杂的,然后说说你对Rust的初印象。

下面的例子是关于基础文本处理:

fn main() 
   let penguin_data = "\\
   common name,length (cm)
   Little penguin,33
   Yellow-eyed penguin,65
   Fiordland penguin,60
   Invalid,data
   ";
 
   let records = penguin_data.lines();
 
   for (i, record) in records.enumerate() 
     if i == 0 || record.trim().len() == 0 
       continue;
     
     
     // 声明一个fields变量,类型是Vec
     // Vec是vector的缩写,是一个可伸缩的集合类型,可以认为是一个动态数组
     // <_>表示Vec中的元素类型由编译器自行推断,在很多场景下,都会帮我们省却不少功夫
     let fields: Vec<_> = record
       .split(',')
       .map(|field| field.trim())
       .collect();
     if cfg!(debug_assertions) 
         // 输出到标准错误输出
       eprintln!("debug: :? -> :?",
              record, fields);
     
 
     let name = fields[0];
     // 1. 尝试把fields[1]的值转换为f32类型的浮点数,如果成功,则把f32值赋给length变量
     // 2. if let是一个匹配表达式,用来从=右边的结果中,匹配出length的值:
     // 当=右边的表达式执行成功,则会返回一个Ok(f32)的类型,若失败,则会返回一个Err(e)类型,if let的作用就是仅匹配Ok也就是成功的情
     // 况,如果是错误,就直接忽略,同时if let还会做一次解构匹配,通过Ok(length)去匹配右边的Ok(f32),最终把相应的f32值赋给length
     // 3. 当然你也可以忽视成功的情况,用if let Err(e) = fields[1].parse::<f32>() ...匹配出错误,然后打印出来,但是没啥卵用
     if let Ok(length) = fields[1].parse::<f32>() 
         // 输出到标准输出
         println!(", cm", name, length);
     
   
 

上面代码中值得注意的Rust特性有:

  • 控制流:forcontinue在一起,实现的循环
  • 方法语法:由于Rust没有继承,因此Rust不是传统意义上的面向对象语言,但是它却从OO语言那里偷师了方法的使用record.trim(),record.split(',')
  • 高阶函数编程: 函数可以作为参数也能作为返回值,例如.map(|field| field.trim()), 这里map使用闭包函数作为参数,也可以称呼为匿名函数lambda函数
  • 类型标注: if let Ok(length) = fields[1].parse::<f32>(), 通过::<f32>的使用,告诉编译器length是一个f32类型的浮点数,这种类型标注不是很常用,但是在编译器无法推断出你的数据类型时,就很有用了
  • 条件编译: if cfg!(debug_assertions),说明下面的输出打印只在debug模式下生效
  • 隐式返回:Rust提供了return关键字用于函数返回,但是在很多时候,我们可以省略它。因为Rust是基于表达式的语言

在终端中运行上述代码时,你会看到很多debug: ...的输出,你也已经了解,这是条件编译, 那么该怎么消除掉这些输出呢?

读者大大肯定都很聪明,已经想到了:是的,在认识Cargo中,曾经介绍过--relese参数,因为cargo run默认是运行的debug模式,如果想要消灭那些debug:输出,我们需要更改为其它模式,其中最常用的模式就是--release也就是生产发布的模式。

具体运行代码就不给了,留给大家作为一个小练习,建议亲自动手尝试下。

至此,Rust安装入门就已经结束,相信看到这里,你已经发现了本书与其它书的区别,其中最大的区别就是:这本书就像优秀的国外课本一样,由浅入深的在带领大家学习Rust,而不是简单的复述一些语言的概念,你可以回忆一下国内的线性代数等计算机教材,都是可以做为对照的反例(当然,不是说这些教材不优秀,只是这些教材需要优秀的老师支撑,而我们并没有)。

以上是关于Rust语言圣经06 - 不仅仅是Hello world的主要内容,如果未能解决你的问题,请参考以下文章

Rust语言圣经12 - 字符串与切片

Rust语言圣经11 - 引用与借用

Rust语言圣经28 - 深入类型转换

Rust语言圣经15 - 元组tuple

Rust语言圣经03 - 安装Rust环境

Rust语言圣经19 - 流程控制