Rust语言教程(2) - 从熟悉的部分开始

虽然有默认不变性还有所有权的问题让Rust一上来用起来有些不同,但是其实大部分语法特点还是我们所熟悉的。
我们没必要上来就跟自己死磕,可以先从我们熟悉的部分开始学习。

一般我们写代码,使用的主要是数据类型、控制结构和函数。我们就从这三部分开始。

数据类型

与Go一样,Rust的定义语句数据也是放在变量名后面的,不过还要加上一个冒号。

布尔类型

布尔类型是bool:

let b0 : bool = true;

因为Rust是有类型推断的功能,所以很多时候可以不用指定类型。

    let b1 = true;let b2 = !b1;let b3 = 1 > 0;println!("{} {} {}",b1,b2,b3);

如果使用CLion等IDE的话,就可以直接看到IDE提供的灰色的类型推断的提示,非常方便:

字符类型 - 传统与现代的结合

Rust的字符类型支持的是Unicode类型,占用4个字节。同时,Rust也支持单字节ASCII值,这时用b开头,类型值就是8位无符号类型u8。

我们来看例子:

    let c1 :char = 'C';let c2:u8 = b'C';let c3 = '中';println!("{} {} {}",c1,c2,c3);

同样,我们可以将字符组成字符串,我们来看例子:

    let s1 = "Hello";let s2 = b"World";println!("{} {:?}",s1,s2);

输出结果为:

Hello [87, 111, 114, 108, 100]

s1的真实类型是str类型,而s2是u8的数组。

    let s1 :&str = "Hello";let s2 :&[u8;5] = b"World";

整数类型: 后缀与下划线齐飞

按照长度,Rust的整数类型支持8位,16位,32位,64位,128位。根据有符号和无符号,分为有符号的i8,i16,i32,i64,i128和无符号的u8,u16,u32,u64,u128。
除此之外,也有根平台相关的类型,有符号为isize类型,无符号为usize类型。

我们看下例子:

    let i1 : i8 = -8;let i2 : i16 = -16;let i3 : i32 = -32;let i4 : i64 = -64;let i5 : i128 = -128;let u1 : u8 = 8;let u2 : u16 = 16;let u3 : u32 = 32;let u4 : u64 = 64;let u5 : u128 = 128;let p1 : isize = -1;let p2 : usize = 1;

上面都是跟其它语言比较像,下面我们来看看Rust特色的后缀。这在C++中也有,比如10l, 200L之类的。
在Rust中,我们直接用类型名做为后缀,我们看个例子:

    let i6 = -1i8;let i7 = -2i16;

这样放在一起可能不太容易区分,没关系,Rust允许我们在数字上任意的加下划线来提升可读性,我们来看几个例子:

    let i08 = -3_i32;let i09 = -4__i64;let i10 = -5___i128;

下划线并非只是用于数字和类型区分,也可以加在数字中间,我们来看个例子:

    let u6 = 1_000_000_u128;println!("{}",u6);

默认的整数类型是i32,如果Rust无法推断中整数的类型,那么就默认为i32.

整数的进制

在Rust中,避免了077这样对八进制的偏爱,改为用0o来表示8进制整数。16进制仍然是0xFF前缀,二进制用0b前缀。

我们看例子:

    let u07 = 0xFF_u32;let u08 = 0o7777_u32;let u09 = 0b01_10_00_u8;println!("{} {} {}",u07,u08,u09);

输出结果为:

255 4095 24

整数的溢出

在C语言中,整数的溢出也是一个常出现的问题。
对此,Rust在debug模式下,在编译时会检查整数的溢出的问题:

    let i_10 : i8 = 0x7f;let i_11 : i8 = i_10 * 10i8;println!("{}",i_11);

在编译时,Rust就会报错:

84 |     let i_11 : i8 = i_10 * 10i8;|                     ^^^^^^^^^^^ attempt to compute `i8::MAX * 10_i8`, which would overflow

懂程序分析的同学可能会想,在编译时检查不出来怎么办?好办,我们在运行时进行检查。
我们来个例子:

    let mut i_20 : i8 = 0x20;for i in 1..20{i_20 = 0x20_i8 * i_20;}println!("{}",i_20);

在运行时仍然发现了溢出:

thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:91:16
stack backtrace:0: rust_begin_unwindat /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:4831: core::panicking::panic_fmtat /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:852: core::panicking::panicat /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:503: tools::testat ./src/main.rs:914: tools::mainat ./src/main.rs:345: core::ops::function::FnOnce::call_onceat /Users/lusinga/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

类型转换

Rust语言是强类型的语言,不像C一样有默认的类型转换。如果进行跨类型计算需要进行类型转换。
类型转换使用“as 类型”的方法来写,我们来看个例子:

let i_100 : i32 = (16i8 + 1) as i32;

i8计算之后还是i8,不能直接赋给i32类型,需要通过as i32来转换类型。

如果计算的类型不同,编译不报错,在运行的时候也会被检查出来。
我们看个例子:

let i_101 = 16i8 + 32i32;

会报下面的错:

error[E0308]: mismatched types--> src/main.rs:99:24|
99 |     let i_101 = 16i8 + 32i32;|                        ^^^^^ expected `i8`, found `i32`

后面还有一个有趣的报错,让trait露了一个爪印:

error[E0277]: cannot add `i32` to `i8`--> src/main.rs:99:22|
99 |     let i_101 = 16i8 + 32i32;|                      ^ no implementation for `i8 + i32`|= help: the trait `Add<i32>` is not implemented for `i8`

浮点数

浮点数跟C语言差不多,分为32位浮点数和64位浮点数,就这两种,分别是f32和f64。默认为f64。
我们来看两个例子:

    let f_01 = 2.1;let f_02 = 2e8;

f_01和f_02都是f64类型。

需要注意的是,对于除0的处理,会引入两个新的值:

  • 对于非0除以0,得到的将是无穷大inf
  • 而对于0除以0,将得到NaN,意思是并不是一个数

我们来看例子:

    let f_03 = 0.0 / 0.0;let f_04 = 1.0 / 0.0;println!("{} {}",f_03,f_04);

输出结果为:

NaN inf

NaN对应的本尊是std::f64::NAN,而inf是std::f64::INFINITY,我们将其排列在一起:

    let f_03 = 0.0 / 0.0;let f_04 = 1.0 / 0.0;let f_05 = std::f64::INFINITY;let f_06 = std::f64::NAN;println!("{} {} {} {}",f_03,f_04,f_05,f_06);

输出结果为:

NaN inf inf NaN

32位和64位的无穷大都是无穷大,它们是相等的:

    let f_10 = std::f32::INFINITY;let f_11 = std::f64::INFINITY;println!("{}",f_11==f_10 as f64);

输出结果为:

true

但是要注意的是,两个NAN是不相等的:

    let f_12 = std::f64::NAN;println!("{}",f_12==f_12);

结果为false.

流程控制

分支语句

Rust支持if-else表达式,用来处理分支。
if后面不必加括号,有点像Go,我们看个例子:

    if n >= 100 {println!("Grade A");}else if n>= 60 {println!("Pass");}else{println!("Fail");}

可以写成更像表达式一点的方式:

    let grade = if n == 100{"A"}else if n>=60{"Pass"}else{"Fail"};

如果用作表达式的话,if和else两个分支返回的结果需要转换成同一类型,毕竟Rust是这么强类型的语言。

循环语句

Rust的循环分为三种:死循环loop,while循环和for循环。

loop最直接干脆,不需要while(true)或者for(;;)这种写法,直接loop。如果需要退出循环就用break,继续下一轮循环就用continue。

我们来个简单例子:

let mut num = 0;let mut sum = 0;loop{if num > 10 {break;}else{sum += num;num += 1;}}println!("sum={}",sum);

我们再将其翻译成while循环:

    num = 0;sum = 0;while num <= 10 {sum += num;num += 1;}println!("sum={}", sum);

与if一样,while后面也不强制要求括号。

最后是for循环,它主要用于迭代器的遍历:

    sum = 0;for i in 0..11  {sum += i;}println!("sum={}", sum);

函数

最后说下函数,Rust的函数使用fn关键字来定义。返回值的类型用->分隔而不是":"。
另外,Rust中不一定非要用return语句来返回值,表达式的值即可,我们看个例子:

fn fib2(n: i32) -> i64 {if n <= 2 {1i64} else {fib2(n - 1) + fib2(n - 2)}
}

按传统写法也是可以的:

fn fib2(n: i32) -> i64 {if n <= 2 {return 1i64} else {return fib2(n - 1) + fib2(n - 2)}
}

或者将return提到if表达式外面:

fn fib2(n: i32) -> i64 {return if n <= 2 {1i64} else {fib2(n - 1) + fib2(n - 2)}
}

小结

在使用基本类型的情况下,Rust跟C语言和Go语言的基础部分其实还是很类似的,熟悉Javascript等语言的同学也不会觉得陌生。我们可以把原有的知识迁移过来,基本类型变量如果需要修改值的话就加个mut。

Rust语言教程(2) - 从熟悉的部分开始相关推荐

  1. Rust语言教程(3) - 数组与向量

    Rust语言教程(3) - 数组与向量 上一节我们采摘了不少低矮的果实,将其它语言学到的知识迁移到Rust 中来.这一节我们仍然继续采摘. 在数据结构中,最经常使用的就是定长的数组和变长的向量. 数组 ...

  2. Rust语言教程(4) - 字符串

    Rust语言教程(4) - 字符串 有了数组和向量的基础,我们再来看它的一个特例:字符串. 字符串有两种表现形式,一种是基本类型,表示字符串的切片,以&str表示:另一种是可变的string类 ...

  3. Rust语言教程(1) - 一门没有GC的语言

    缘起 本来这一系列文章并不在计划中.昨天跟赵磊和七哥讨论没有GC管理内存的问题. 讨论到没有GC情况下管理内存的学习曲线,七哥认为学习曲线不陡而是使用曲线陡.诚然,如果只有malloc和free,确实 ...

  4. 【一天一门编程语言】Rust 语言程序设计极简教程

    文章目录 Rust 语言程序设计极简教程 介绍 安装 Rust Hello, World 基础语法 变量及数据类型 控制结构 `if` 语句 `while` 语句 `for` 语句 函数 泛型 泛型的 ...

  5. Rust学习教程02 - Rust语言简介

    本文节选自<<Rust语言圣经>>一书 欢迎大家加入Rust编程学院,一起学习交流: QQ群:1009730433 进入Rust编程世界 一.Rust发展历程 Rust 最早是 ...

  6. 《安富莱嵌入式周报》第283期:全开源逆向“爆破”硬件工具,Linux内核6.1将正式引入RUST语言,I3C培训教程,80款市场成熟的电感式位置传感器设计

    往期周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - P ...

  7. 微软再推 Rust 语言免费中文教程,更香了!

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! 在过去的几个月,Amazon.Facebook.微软以及谷歌等科技巨头正疯狂吸纳人才市场上的 Rust 语言程序员 ...

  8. 【Rust 日报】2022-01-09 又一个Rust中文教程《Rust语言圣经》

    12个Rust的Tips 使用 Cow<str> 作为返回类型 使用 Crossbeam channels 取代标准库 使用 Scopeguard 实现类似 Golang 的延迟运算 使用 ...

  9. RUST语言的编程范式

    总是有很多很多人来问我对Rust语言怎么看的问题,在各种地方被at,其实,我不是很想表达我的想法.因为在不同的角度,你会看到不同的东西.编程语言这个东西,老实说很难评价,在学术上来说,Lisp就是很好 ...

  10. rust语言为什么没人用_为什么Rust语言正在兴起

    rust语言为什么没人用 您可能从未用Mozilla创建的开源,系统级编程语言Rust编写任何东西,但是您可能会在某个时候写. 在Stack Overflow的2019年开发人员调查中 ,开发人员将R ...

最新文章

  1. 常用HTTP状态码趣(曲)解
  2. 用diff命令制作补丁
  3. ubuntu系统下安装php环境
  4. Java ObjectInputStream enableResolveObject()方法与示例
  5. 修改gitignore 后不起作用
  6. ASCII中关于大小写字母间隔为32的思考
  7. 【Vue】v-if 、v-show、v-for指令,最基础的流程控制和循环处理
  8. error:无法定位软件包
  9. 命令修改本地计算机策略,命令行修改本地组策略_通过命令行从Windows进行本地组管理...
  10. CGAL学习之路(三):CGAL读写点云
  11. 安装nodejs时:The error code is 2503.
  12. 两块同步FIFO实现乒乓操作
  13. 藏苹果 HNSUT 1889
  14. 金色css颜色代码大全,CSS颜色代码大全
  15. java基础语言+面向对象_经典案例——65个
  16. 移动互联网时代代驾app开发未来走向功能定制化
  17. 【Unity】物体爆炸,碎片横飞
  18. Advanced IP Scanner –免费的轻量级Windows端口扫描器
  19. saiku 安装配置
  20. 珍爱网退费流程?珍爱网怎么退费

热门文章

  1. 自制一款可搜索图片、设置页面背景的浏览器插件
  2. 【day23】The field file exceeds its maximum permitted size of 1048576 bytes.
  3. spss 描述性分析
  4. SPSS——描述性统计分析——描述
  5. 微信网页开发调试的一些方法
  6. Win10利用bat文件实现文件与文件夹批量重命名
  7. 小森林顺序_电影:《小森林》两部
  8. php文字如何排版,文字如何实现完美UI?文本排版设计告诉你
  9. unity屏幕分辨率设置
  10. PC端 VUE 官网项目 前端开发 响应式布局(宽+高 等比例缩放)