类型、运算符和字符串 - 基础类型
像其他现代编程语言一样,Rust提供了一系列基础的类型,我们一般称之为原生类型。其强大的类型系统就是建立在这些原生类型之上的,因此,在写Rust代码之前,必须要对Rust的原生类型有一定的了解。
bool
Rust自带了bool
类型,其可能值为true
或者false
。
我们可以通过这样的方式去声明它:
let is_she_love_me = false;
let mut is_he_love_me: bool = true;
当然,bool类型被用的最多的地方就是在if表达式
里了。
char
在Rust中,一个char
类型表示一个Unicode字符,这也就意味着,在某些语言里代表一个字符(8bit)的char,在Rust里实际上是四个字节(32bit)。
同时,我们可以将各种奇怪的非中文字符随心所欲的赋值给一个char类型。需要注意的是,Rust中我们要用'
来表示一个char,如果用"
的话你得到的实际上是一个&'static str
。
let c = 'x';
let cc = '王';
数字类型
和其他类C系的语言不一样,Rust用一种符号+位数的方式来表示其基本的数字类型。可能你习惯了int
、double
、float
之类的表示法,Rust的表示法需要你稍微适应一下。
你可用的符号有 i
、f
、u
你可用的位数,当然了,都是2的n次幂,分别为8
、16
、32
、64
及size
。
你可以将其组合起来,形成诸如i32
,u16
等类型。
当然了,这样的组合并不自由,因为浮点类型最少只能用32位来表示,因此只能有f32
和f64
来表示。
自适应类型
看完上面你一定会对isize
和usize
很好奇。这两个是来干啥的。这两个嘛,其实是取决于你的操作系统的位数。简单粗暴一点比如64位电脑上就是64位,32位电脑上就是32位,16位……呵呵哒。
但是需要注意的是,你不能因为你的电脑是64位的,而强行将它等同于64,也就是说isize != i64
,任何情况下你都需要强制转换。
数组 array
Rust的数组是被表示为[T;N]
。其中N表示数组大小,并且这个大小一定是个编译时就能获得的整数值,T表示泛型
类型,即任意类型。我们可以这么来声明和使用一个数组:
let a = [8, 9, 10];
let b: [u8;3] = [8, 6, 5];
print!("{}", a[0]);
和Golang一样,Rust的数组中的N
(大小)也是类型的一部分,即[u8; 3] != [u8; 4]
。这么设计是为了更安全和高效的使用内存,当然了,这会给第一次接触类似概念的人带来一点点困难,比如以下代码。
fn show(arr: [u8;3]) {
for i in &arr {
print!("{} ", i);
}
}
fn main() {
let a: [u8; 3] = [1, 2, 3];
show(a);
let b: [u8; 4] = [1, 2, 3, 4];
show(b);
}
编译运行它你将获得一个编译错误:
<anon>:11:10: 11:11 error: mismatched types:
expected `[u8; 3]`,
found `[u8; 4]`
(expected an array with a fixed size of 3 elements,
found one with 4 elements) [E0308]
<anon>:11 show(b);
^
<anon>:11:10: 11:11 help: see the detailed explanation for E0308
error: aborting due to previous error
这是因为你将一个4长度的数组赋值给了一个只需要3长度数组作为参数的函数。那么如何写一个通用的show方法来展现任意长度数组呢?请看下节Slice
Slice
Slice
从直观上讲,是对一个Array
的切片,通过Slice
,你能获取到一个Array
的部分或者全部的访问权限。和Array
不同,Slice
是可以动态的,但是呢,其范围是不能超过Array
的大小,这点和Golang是不一样的。
一个Slice
的表达式可以为如下: &[T]
或者 &mut [T]
。
这里&
符号是一个难点,我们不妨放开这个符号,简单的把它看成是Slice
的甲鱼臀部——规定。另外,同样的,Slice
也是可以通过下标的方式访问其元素,下标也是从0开始的哟。
你可以这么声明并使用一个Slice
:
let arr = [1, 2, 3, 4, 5, 6];
let slice_complete = &arr[..]; // 获取全部元素
let slice_middle = &arr[1..4]; // 获取中间元素,最后取得的Slice为 [2, 3, 4] 。切片遵循左闭右开原则。
let slice_right = &arr[1..]; // 最后获得的元素为[2, 3, 4, 5, 6],长度为5。
let slice_left = &arr[..3]; // 最后获得的元素为[1, 2, 3],长度为3。
怎么样,了解了吧。
那么接下来我们用Slice
来改造一下上面的函数
fn show(arr: &[u8]) {
for i in arr {
print!("{} ", i);
}
println!("");
}
fn main() {
let a: [u8; 3] = [1, 2, 3];
let slice_a = &a[..];
show(slice_a);
let b: [u8; 4] = [1, 2, 3, 4];
show(&b[..]);
}
输出
1 2 3
1 2 3 4
动态数组 Vec
熟悉C++ STL的同学可能对C++的vector很熟悉,同样的,Rust也提供了一个类似的东西。他叫Vec
。
在基础类型里讲Vec
貌似是不太合适的,但在实际应用中的应用比较广泛,所以说先粗略的介绍一下,在集合类型的章节会有详细讲述。
在Rust里,Vec
被表示为 Vec<T>
, 其中T是一个泛型。
下面介绍几种典型的Vec
的用法:
let mut v1: Vec<i32> = vec![1, 2, 3]; // 通过vec!宏来声明
let v2 = vec![0; 10]; // 声明一个初始长度为10的值全为0的动态数组
println!("{}", v1[0]); // 通过下标来访问数组元素
for i in &v1 {
print!("{}", i); // &Vec<i32> 可以通过 Deref 转换成 &[i32]
}
println!("");
for i in &mut v1 {
*i = *i+1;
print!("{}", i); // 可变访问
}
输出结果:
1
123
234
最原生字符串 str
你可以用str
来声明一个字符串,事实上,Rust中,所有用""
包裹起来的都可以称为&str
(注意这个&
,这是难点,不用管他,不是么?),但是这个类型被单独用的情况很少,因此,我们将在下一节着重介绍字符串类型。
函数类型 Functions
函数同样的是一个类型,这里只给大家普及一些基本的概念,函数类型涉及到比较高阶的应用,希望大家能在后面的闭包
章节仔细参读
下面是一个小例子
fn foo(x: i32) -> i32 { x+1 }
let x: fn(i32) -> i32 = foo;
assert_eq!(11, x(10));