搭建好了开发环境之后,就算是正式跳进Rust的坑了,今天我就要开始继续向下挖了。

由于我们初来乍到 ,对Rust还不熟悉,所以我决定先走一遍常规套路。

变不变的变量

学习一门语言第一个要了解的当然就是变量啦。Rust使用关键字let来定义变量。我们写一个简单的demo

so easy!等等,这个小红线是怎么回事?编译错误???别着急,哪里不对点哪里。

IDEA告诉我,这个错误是

Cannot assign twice to immutable variable [E0384]

不可变的变量不能赋值两次。我定义的变量是不可变的?这能叫变量?

官方文档对此的解释是,对于一个变量,你在一部分代码中不希望它改变,而在另一部分代码中修改了它。那么第一部分代码的运行结果也许就不符合预期了。所以Rust的编译器为了杜绝这种情况,也就是说Rust的变量默认是不可修改的。也就是说你只能对它赋值一次,之后它就是只读的了。有点像Java中的final变量。嗯…很严格。

但我们编程中还是需要变量的,怎么办?下面是跟着IDEA学习写代码环节。直接使用Alt + Enter,IDEA会在定义x时加上mut关键字。

果然不会报错了。感谢IDEA。接下来运行试试

The value of x is: 5
The value of x is: 6

打印结果符合我们的预期。

mut关键字在官方文档也有解释,定义变量时加上mut,表明这个变量是一个可变变量。Rust之所以设计了可变变量,还有一个比较重要的原因就是,对于比较复杂的数据类型,每次修改都要复制并且分配新的内存。这种性能损耗有时候是无法接受的。因此可以选择使用可变变量来提高性能。

变量和常量

Rust本身也支持常量,可能大多数同学和我有一样的疑问,常量和不可变变量有什么区别呢?

事实上它们还是有区别的。最明显的就是名字不一样。(这是一句废话)

主要的区别有以下几种:

  1. 定义常量时不能使用mut关键字
  2. 常量定义使用的关键字是const,并且需要指定数据类型。定义变量使用的是let
  3. 常量可以在任何范围内定义,并且可以在多个代码块中使用
  4. 给常量赋值时,不能使用函数的返回值或者是计算式。只能使用一个「常量」

变量的覆盖

Rust是一门静态编程语言,对于大多数静态编程语言中,在同一范围内,变量名是不允许重复的。但是Rust允许这样定义。类似于这样:

fn main() {
let x = 5; let x = x + 1; let x = x + 2; println!("The value of x is: {}", x);
}

这让人看起来有些疑惑,作为一个Java程序员,在我看来第二行就应该报编译错误了。但我们刚提到了Rust是允许这样定义的。对于上述代码来讲,每次定义x都会覆盖前一次定义的x。

对于Java来讲,将一个int类型的变量转换成String类型的变量可能需要这样做:

int codeInt = 1;
String codeStr = String.valueOf(codeInt);

我们需要定义两个变量来分别接收不同类型的变量,为了变量名更有意义,可能要在变量名中加上变量类型。而在Rust中就不用考虑这个问题。

let s = "123";
let s: u32 = s.parse().expect("Not a number!");

这样定义之后,再使用变量s时,它都是u32类型的变量了。

上面这个例子就是覆盖变量和可变变量的区别:可变变量不可以修改变量类型,覆盖变量可以做类型转换。

数据类型

可能有些同学不太理解Rust为什么是静态语言。这是因为在编译阶段,Rust编译器必须要明确每个变量的类型。编译器通常会根据变量的值或者使用方法来为变量指定一个数据类型。如果某个变量可能的数据类型有多个,那么就需要开发者手动指定。

像上一节的例子中,第二次定义s如果不指定类型u32,编译就会报错。Rust支持的数据类型都有哪些呢?

和多数编程语言一样,Rust支持的数据类型可以分为基本数据类型复合数据类型两大类。先说基本数据类型,基本数据类型分为整数型、浮点型、布尔型和字符型。我们逐个介绍一下。

整数型

Rust支持的整数类型分为有符号整数和无符号整数

Length Signed Unsigned
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

如果没有指定数据类型,Rust默认使用i32,这个类型通常是性能最好的。

再顺便聊一下整数的几种表示。

Number literals Example
Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
Byte(u8) b'A'

十进制中_一般被当作千分符。

浮点型

Rust的浮点类型不像整型那么多,它只支持两种:f32和f64分别表示32位和64位浮点数,默认的浮点类型是f64。

布尔类型

布尔类型没有什么特别的,Rust支持隐式和显式声明两种

let t = true;

let f: bool = false;

字符型

需要注意的是字符类型char使用单引号,字符串使用双引号。字符类型的值可以是Unicode标准值。范围是从U+0000到U+D7FF和U+E000到U+10FFFF。这意味着它可以是中文韩文 emoji等等,而并不局限于直觉上的「字符」。

聊完了基本数据类型,再来聊一聊复合类型,Rust包含两种复合类型:Tuple和Array。

Tuple类型

Tuple是一种可以存储不同类型的数字的集合。它的长度固定。声明方法是:

let tup: (i32, f64, u8) = (500, 6.4, 1);

如果想要取得tuple中的某一个值,通常有两种方法,一种是将tuple分别赋值给多个变量

fn main() {
let tup = (500, 6.4, 1); let (x, y, z) = tup; println!("The value of y is: {}", y);
}

另一种方法是用直接用「.」来取值。

fn main() {
let tup = (500, 6.4, 1); let x = tup.0; let y = tup.1; let z = tup.2; println!("x: {}, y: {}, z: {}", x, y, z);
}

Array类型

Array也是多个值的集合,但与Tuple不同的是,Array中的各个元素的数据类型必须相同。Array的长度也是固定的,这点上Rust的Array和其他语言的有所不同。Array的定义方法是:

fn main() {
let a = [1, 2, 3, 4, 5];
}

Rust的数组存储在栈中,而不是堆。如果你不能在定义时确定数组的长度,那么需要使用vector类型,这个我们在后面讨论。Array还有一些其他的定义方法。

let a: [i32; 5] = [1, 2, 3, 4, 5];

i32表示数组中元素的类型,5表示元素数量。

如果初始化时所有元素的值都相同,还可以这样定义:

let a = [3; 5];

这表示定义一个长度为5的数组,每个元素都是3。

代码写在哪——函数

函数在每个编程语言中都是基本的概念,因此我们不做过多赘述。Rust定义函数的方法是:

fn main() {
let a = 1; let b = 2; let sum = add(a,b); println!("The value of sum is: {}", sum);
} fn add(x: i32, y: i32) -> i32 {
x + y
}

Rust在定义函数时,需要指定参数的名称和类型和返回值的类型。而返回值只能是表达式。作为函数返回的表达式是不能以分号结尾的。

该往哪走——流程控制

Rust的流程控制语句包括条件控制语句和循环语句。条件控制语句有if,循环语句包括loop、while和for。

if

Rust中if的条件必须是bool类型,它不像js中,会自动将变量转换成bool类型。此外,if还可以用于let语句中。例如:

let number = if condition {
5
} else {
6
};

这种方式需要注意的是,每个表达式中返回的值必须是同一类型的。

loop

loop循环中,如果没有break或者是手动停止,那么它会一直循环下去。写法很简单。

loop {
println!("again!");
}

loop的用处是它可以有返回值

let result = loop {
counter += 1; if counter == 10 {
break counter * 2;
}
};

while

while循环是当条件成立时进入循环。

while number != 0 {
// do something
}

for

当我们需要遍历数组时,可以使用for循环。

for element in a.iter() {
println!("the value is: {}", element);
}

总结

以上,是Rust的一些基本概念。和其他的编程语言大同小异,记得一些特殊的地方就好,例如变量的不可变性。我们还有一些数据类型没有涉及,比如vector,String等,这些会在后面详细讲解。

至此,我已经又向下挖了一层了。不知道你入坑了没有?已经入坑的同学还请麻烦帮忙往外刨(分)土(享)。

Rust入坑指南:常规套路的更多相关文章

  1. Rust入坑指南:核心概念

    如果说前面的坑我们一直在用小铲子挖的话,那么今天的坑就是用挖掘机挖的. 今天要介绍的是Rust的一个核心概念:Ownership.全文将分为什么是Ownership以及Ownership的传递类型两部 ...

  2. Rust入坑指南:鳞次栉比

    很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑.没错,就是要介绍一些集合类型的数据类型."鳞次栉比"这个标题是不是显得很有文化? 在Rust入坑指南:常规套路一文中我们已经介绍 ...

  3. Rust入坑指南:亡羊补牢

    如果你已经开始学习Rust,相信你已经体会过Rust编译器的强大.它可以帮助你避免程序中的大部分错误,但是编译器也不是万能的,如果程序写的不恰当,还是会发生错误,让程序崩溃.所以今天我们就来聊一聊Ru ...

  4. Rust入坑指南:朝生暮死

    今天想和大家一起把我们之前挖的坑再刨深一些.在Java中,一个对象能存活多久全靠JVM来决定,程序员并不需要去关心对象的生命周期,但是在Rust中就大不相同,一个对象从生到死我们都需要掌握的很清楚. ...

  5. Rust入坑指南:齐头并进(上)

    我们知道,如今CPU的计算能力已经非常强大,其速度比内存要高出许多个数量级.为了充分利用CPU资源,多数编程语言都提供了并发编程的能力,Rust也不例外. 聊到并发,就离不开多进程和多线程这两个概念. ...

  6. Rust入坑指南:坑主驾到

    欢迎大家和我一起入坑Rust,以后我就是坑主,我主要负责在前面挖坑,各位可以在上面看,有手痒的也可以和我一起挖.这个坑到底有多深?我也不知道,我是抱着有多深就挖多深的心态来的,下面我先跳了,各位请随意 ...

  7. Rust入坑指南:千人千构

    坑越来越深了,在坑里的同学让我看到你们的双手! 前面我们聊过了Rust最基本的几种数据类型.不知道你还记不记得,如果不记得可以先复习一下.上一个坑挖好以后,有同学私信我说坑太深了,下来的时候差点崴了脚 ...

  8. Rust入坑指南:海纳百川

    今天来聊Rust中两个重要的概念:泛型和trait.很多编程语言都支持泛型,Rust也不例外,相信大家对泛型也都比较熟悉,它可以表示任意一种数据类型.trait同样不是Rust所特有的特性,它借鉴于H ...

  9. Rust入坑指南:有条不紊

    随着我们的坑越来越多,越来越大,我们必须要对各种坑进行管理了.Rust为我们提供了一套坑务管理系统,方便大家有条不紊的寻找.管理.填埋自己的各种坑. Rust提供给我们一些管理代码的特性: Packa ...

随机推荐

  1. CF990B Micro-World 贪心 第十六

    Micro-World time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...

  2. .gitignore文件失效的解决方案

    通常在idea中,我们使用git进行项目管理的时候,一些不需要的文件如.idea,.target文件不需要上传至gitlab仓库,这时,就需要在项目中定义一个.gitignore文件,用来标识这些文件 ...

  3. [系列] go-gin-api 路由中间件 - 捕获异常(四)

    概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常.当系统发生异常时,提示 "系统异常,请联系管理员!",同时并发送 ...

  4. Linux 安装二进制MySQL 及 破解MySQL密码

    1.确保系统中有依赖的libaio 软件,如果没有: yum -y install libaio 2.解压二进制MySQL软件包 tar xf mysql-5.7.24-linux-glibc2.12 ...

  5. MySQL二进制日志挖掘器BinlogMiner 1.0发布了。

    MySQL从2014年开始超越SQL Server, 占据DB-Engines数据库流行度排行榜第二名, 是一种非常流行的关系型数据库, 特别是在互联网领域, 是一种应该掌握的数据库系统.最近在学My ...

  6. asp.net core webapi 统一处理返回值、异常和请求参数验证

    现在的开发模式很少用asp.net mvc一个项目直接操作界面和数据库了.大部分都使用前后端分离,更多的是为了让API支持移动端. 后端写webapi的时候必然需要和前端约定请求值和返回值的格式,如果 ...

  7. 微软发布.Net Core 3.0 RC1,最终版本定于9月23日

    2019.9.17 微软 宣布推出.NET Core 3.0 Release Candidate 1.就像Preview 9一样,主要专注于为 .NET Core 3.0 发布最终版本 .现在变得非常 ...

  8. Winform中实现ZedGraph中曲线右键显示为中文

    场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  9. 1、Spark 2.1 源码编译支持CDH

    目前CDH支持的spark版本都是1.x, 如果想要使用spark 2x的版本, 只能编译spark源码生成支持CDH的版本. 一.准备工作 找一台Linux主机, 由于spark源码编译会下载很多的 ...

  10. Kylin配置Spark并构建Cube

    HDP版本:2.6.4.0 Kylin版本:2.5.1 机器:三台 CentOS-7,8G 内存 Kylin 的计算引擎除了 MapReduce ,还有速度更快的 Spark ,本文就以 Kylin ...