上篇文章中我们学了rust
的变量、变量的可变性(mutability
)、常量以及shadowing
。没看过可以看下
今天我们接着往下学。
还是昨天那个项目
rust
是一门静态强类型语言,所以任何的变量的类型都需要在编译时确定下来。
与它相反的则是动态弱类型。我们都熟悉的javascript
就是,类型是在runtime
的时候才确定的,边解析边执行。当然,有typescript
[2]之后舒服一些。
你在写js
代码的时候是否会经常头疼没有代码提示,比如变量类型、函数用法等?那就是因为js
是runtime
的时候才进行解析。
所以在rust
中,变量需要定义类型。 当然,也不是说非得每个变量都得你去写个类型才行,这多累。rust
在编译(compile
)的时候会根据你的值(value
)推测出你的变量是什么类型的,所以大部分情况下你是不需要去手动写类型的。
但是有的情况它是没法去确定的,还记得我们之前的学习过程中遇到的强制你声明变量类型的报错吗[3]?
这是因为parse
可以转换的类型不止一种,可能是num
又或者是bool
等,这是不符合预期的,所以这里会强制你设置变量的类型,这样runtime
的时候才能知道要parse
成什么。
定义变量类型很简单,和写typescript
一样,只需在变量后等号前: xxx
即可。
scalar types
)可以简单的理解为js
中的基础数据类型,比如number、boolean
等,也就是简单的数据类型。
在rust
中有四种标量类型:integers、floating-point-numbers、Booleans、characters
,也就是:整数类型、浮动类型也就是带有小数的数字类型、布尔类型以及字符类型。
整数类型,上面parse
那行代码中用的i32
即是一个整数类型。但如果你看过之前的文章,应该会看到另一个类型u32
。实际上他俩都是表示的整数类型。
为什么一个整数有两种类型呢?因为在计算机中负数并不是我们现实生活中的负数,而是一个带符号(二进制最高位置为1)的“正数“。
i
就是integer
,可用来定义正负数,而u
表示unsigned
,表示无符号的,只能用来定义正数。32
表示32
位。 类似的还有如下
其中arch
表示的是根据你操作系统来判断,比如64位的就是i64
和u64
。
integer
范围是根据类型定义时的位数来变化的,带符号的正数类型可存储范围为-(2^n - 1)
到(2^n - 1) - 1
,而无符号的只能存储0 - (2^n) - 1
范围之间。
比如i8
表示-128 ~ 127
。而u8
则是0 ~ 255
。
另外rust
中还有一种有趣的写法,不用去定义类型,可以把类型放到value
中,比如:
123u8
表示数据是123
,是u8
类型的整数。
另一个有趣的写法是利用下划线把一个数字写的更方便阅读,比如:
10_000
和10000
是同一个效果,但是可阅读性高了很多。
另外还有一点需要注意,那就是溢出的情况[6]。
开发模式下如果你的数字溢出,会直接崩溃。而生产环境不会,会变成超出的那个值。比如u8
类型设置一个266
数值,在开发模式下会报错,但是生产环境下会变成9。
最后,整数的默认类型是i32
。
floating-point-numbers types
浮动类型。
有f32
、f64
以及fsize
三种浮动类型。
默认是f64
,因为速度快精度高(双精度)。
然后没啥好说的了,该说的integer
里面说的差不多了。
数字用的最多的地方自然就是计算,rust
中的几种运算和其它语言一致,所以这里简单的过一下即可。
布尔类型
在rust
中布尔类型占位一个字节,用bool
定义布尔变量
完了~
字符类型
顾名思义,只有是一个字符的时候才算是character
。
超了直接报错,另外如果需要设置字符类型得用单引号,不然默认被认为是&str
字符串类型。
其它其实也没什么好说的了,和其它语言其实差不多,包含包括ASCII
\多种语言字符`emoji`等。
不过需要注意点一点是范围在``U+0000to
U+D7FF、U+E000to
U+10FFFF`之间,如果不在这个范围内,那就很有可能是乱码。
其实字符并非是一个Unicode
的概念,所以在代码中可能会和你的想法有出入[9]。
需要我们留意的一点就是字符串和字符不是同一个东西,字符串有自己的类型,后面会说到,这里就先不说了。
compound types
)标量类型就说完了,现在我们来看下复合类型。
他们的区分其实挺好区分,标量类型只有一种数据又或者是结构,而复合类型允许多个数据或者结构放在同一个变量中。
在rust
中有两种原始的复合类型:Array
和tuple
也就是数组和元组。
元组相信大家都不陌生了,可以用来存储各种类型的值,不过有个点需要注意就是元组的长度是固定的,无法在定义后新增或者删除元素之类的。
直接来看下例子
cargo run
一下
是不是很像python
的元组?
那么问题来了,要怎么获取其中一个元素。
有两种方式:
es6+
的方法。但是挺蛋疼的是解构需要给出所有的变量才行,比如我只想解构第一个元素,这样是不行的。
第一种方法有些麻烦,所以基本上都是用的下标获取这种方式。
元组下标从0
开始。
元组的默认值是一个()
,表示empty
,他们叫他unit
,表达式默认返回值就是一个unit
,(impilcitly
不明显滴)。
数组相信大家都很熟悉了
不过比起在js
中,rust
的array
被设定为只能包含同一种类型的元素,也就是数组里的元素都得是同个类型。 同样的,它的长度也得是固定的,也是不能新增或者移除元素。
来看下代码
定义元素类型
格式为type; len
。毕竟类型得一样,长度不可变。
这里还有一种快捷初始化数组的方式
格式为[value; len]
。等价于[3, 3, 3, 3, 3]
。
获取元素的方式和元组差不多
同样是需要全部解构才行
不过这种方式有一个大问题,那就是数组越界。
数组越界
java
中应该是有同样的概念,指的是使用的下标超出数组的长度从而引发的错误。在c/c++
中是允许读取超出数组自身长度的,不过数据有没有问题就不是它们的事了。。。
为什么会有这种错误呢?
在rust
中,数组是基于stack
也就是栈实现的,毕竟空间固定不允许拓展。而栈的空间是连续的,毕竟LIFO
。而栈相邻的空间是不知道是啥的,所以这个时候下标超了数据就错了。
例子就不看了,直接看下报错。
什么情况下会有这种错误?
当下标是一个变量比如从stdin
中获取的,这时就会有可能有问题,而且这个问题并不能在编译过程中发现,这是一个runtime error
,因为你并不能确定用户输入了什么(客户在酒吧点了一份炒饭然后酒吧炸了~[14])。
如果想让数组变化的话可以用vector
[15],由标准库提供,可改变数组长度等。官方也是很建议用这个vector
,如果你不知道用哪个,优先vector
。
先来看下如何使用,具体分析后面会说到。
同样是要求元素类型一样,但是可以伸缩(误)。
新增元素和其他语言差不多,都是push
,不过有个点需要注意就是数组自身得是mut
的。
今天我们学习了rust
中的标量类型和原始复合类型。
感觉东西很少,但是就是有些累。。。可能是上班遇到了个蛇皮需求。。。
老规矩如果觉得对你有用麻烦点个赞,谢谢~
编辑于 2022-11-30 16:12・IP 属地广东