Rust 类型学习笔记
笔记要点:
- 掌握 Rust 语言基本的类型
Rust 语言基础数据类型(Primitive Types)主要有如下几类:
标量
整数
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 |
浮点数:f32, f64
。
整数使用示例:
fn main() {
let a: i32 = 10;
let f = 3.14;
let b = 5i8;
let c = 100_000_000;
let pi = 3.141_592_653_59f64;
let y = a + f;
println!("{}", y);
}
从以上例子可以总结如下几个要点:
- 可以在字面值后面接类型:
let b = 5i8;
- 可以用下划线分割数字以提高可读性。
- 可以不用写类型提示,而使用类型推导。
但运行以上代码会报错:
error[E0277]: cannot add `{float}` to `i32`
--> src\main.rs:29:15
|
29 | let y = a + f;
| ^ no implementation for `i32 + {float}`
|
= help: the trait `Add<{float}>` is not implemented for `i32`
error:
这是因为 Rust 语言不支持数字类型的隐式转换,使用 as
进行类型转换:
fn main() {
let a: i32 = 10;
let f = 3.14;
let y = a as f32 + f;
println!("{}", y); // 13.14
}
字符:char
fn main() {
let x = 'x';
let y: char = '😎';
let zh = '中';
println!("{}: {}", x, x.len_utf8());
println!("{}: {}", y, y.len_utf8());
println!("{}: {}", zh, zh.len_utf8())
}
运行代码:
x: 1
😎: 4
中: 3
以上示例表明 Rust 的字符是 Unicode 字符。注意字符要用单引号。
布尔型:bool
布尔类型只有两个值:true, false
,不能把 0, None
等用作布尔型。
let is_active = true;
let has_finished: bool = false;
单位类型(unit type): ()
常用作表达式的默认返回值,一个表达式没有显示返回值,就默认返回 ()
。
fn plus_one(x: &i32) {
let y = x + 1;
// do something else
}
fn main() {
let x = 42i32;
println!("{:?}", plus_one(&x)); // ()
}
组合类型
数组(array):[T; length]
use std::mem;
fn main() {
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
println!("index 0: {}", numbers[0]);
println!("out of index: {}", numbers[5]);
println!("length: {}", numbers.len());
println!(
"i32: {} bytes, numbers array: {} bytes",
mem::size_of_val(&0i32),
mem::size_of_val(&numbers)
);
let zeros = [0i32; 5];
println!("{:?}", zeros);
}
运行以上代码会报错:
error: this operation will panic at runtime
--> src\main.rs:6:34
|
6 | println!("out of index: {}", numbers[5]);
| ^^^^^^^^^^ index out of bounds: the length is 5 but the index is 5
|
= note: `#[deny(unconditional_panic)]` on by default
error:
这是因为我们故意卖了一个破绽:println!("out of index: {}", numbers[5]);
,注释本行后运行:
index 0: 1
length: 5
i32: 4 bytes, numbers array: 20 bytes
[0, 0, 0, 0, 0]
📝要点总结:
(1)数组声明需要指定元素类型与元素个数,元素个数在编译时就确定了,运行时不能改变。数组在内存上表现为一段连续的内存,访问数组元素的时间复杂度为常数。
(2)类型提示可以使用类型推导而省略。
(3)Rust 语言不允许数组越界。
接下来我们学习一种与数组紧密相关的类型:
切片(slice)
先看一个例子:
fn main() {
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
let skip_first = &numbers[1..];
println!("&numbers[1..]: {:?}", skip_first);
println!("&numbers[1..3]: {:?}", &numbers[1..3]);
println!("&numbers[..3]: {:?}", &numbers[..3]);
println!("&numbers[..]: {:?}", &numbers[..]);
}
运行可以得到:
&numbers[1..]: [2, 3, 4, 5]
&numbers[1..3]: [2, 3]
&numbers[..3]: [1, 2, 3]
&numbers[..]: [1, 2, 3, 4, 5]
📝 要点总结:
(1)切片就是数组的一部分,相当于一个子数组。
(2)切片的规则遵循左闭右开惯例:$[start, end)$。
(3)利用切片可以非常方便的截取数组。
字符串切片(&str)
字符串是 Rust 语言的一个难点。事实上,字符串类型是每种语言用得最多的类型,因为计算机本质上是为人服务的。某些底层语言例如 C 语言处理字符串是相当痛苦的,因为它把字符串当做数组处理,由此带来许多问题:数组大小不可变,数组越界等,而且字符串相关的函数用起来也不是很方便。许多高级语言对字符串进行了封装,其中接口清晰、好用的是 JavaScript String,建议通过这个学习字符串。
Rust 语言常用的字符串分为两种:一种是字符串切片(&str),另一种是堆字符串(String),先看例子:
fn main() {
// example 1
let hello = "你好";
let rust: &'static str = "Rust";
println!("{}, {}", hello, rust); // 你好, Rust
// example 2
println!("{}", hello.len()); // 6
println!("{}", hello.chars().count()); // 2
println!("{}", hello.is_empty()); // false
// example 3
// println!("{}", hello[0]);
println!("{:?}", &hello[..3]); // "你"
// example 4
let path = "/home/root/rust \n";
println!("{:?}", path.starts_with("/")); // true
println!("{:?}", path.trim()); // "/home/root/rust"
}
📝 要点总结:
(1)例1表明 Rust 字符串字面值是 &'static str
,'static
表示该字符串具有静态生命周期。
(2)例2表明 Rust 字符串长度与字符个数是两码事。
(3)例3展示了切片的用法,可以尝试切一下 &hello[..2]
,看看会发生什么。
(4)例4展示了一些有关字符串处理的方法,更多方法请阅读 str。
补充:堆字符串用法:
fn main() {
let mut hello = String::from("你好");
hello.push_str(", rust");
println!("{:?}", hello); // "你好, rust"
println!("{:?}", hello + ", 嗯mua"); // "你好, rust, 嗯mua"
let mut result = String::new();
result = format!("{} + {} = {}", 600, 66, 600 + 66);
println!("{:?}", result); // "600 + 66 = 666"
}
如果你不知道用哪个,可以使用如下策略:
(1)常字符串:不变的,能放进源代码里的就用 &str
;
(2)堆字符串:可变的,从网络,文件系统、用户输入获取的字符串就用堆字符串。
💡 约定:以后我们把堆字符串简称为字符串,常字符串,静态字符串,字符串切片都表示 &str
。
元组(tuple):(T1, T2, ...)
fn main() {
let a: (i32, f64, bool, char) = (1, 1.5, true, 'a');
println!("{:?}", a);
let complex = (0, 1);
println!("real:{}, image: {}", complex.0, complex.1);
let (real, image) = complex;
println!("complex= {} + {}i", real, image);
let matrix = ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0));
println!("{:?}", matrix);
let (first_row, _) = matrix;
println!("first row: {:?}", first_row);
}
运行上述程序:
(1, 1.5, true, 'a')
real:0, image: 1
complex= 0 + 1i
((1.0, 2.0, 3.0), (4.0, 5.0, 6.0))
first row: (1.0, 2.0, 3.0)
📝 要点总结:
(1)可以看到,元组是由()
组织起来的一个整体,它的元素类型可以不同。
(2)第二个例子我们用元组表示一个虚数:把第一个元素当做实部,把第二个元素当做虚部。可以看到元组获取元素的方法是 complex.0
。
(3)可以用类似 let (real, image) = complex;
的方法解构(Destruct)元组并把相应的值绑定到某些变量,不用的值可以用 _
跳过。
更多资料
- 官网文档:doc.rust-lang.org/std/index.html#p...
- 学习博客:learning-rust.github.io/docs/a8.pr...
- 官方示例:doc.rust-lang.org/rust-by-example/...
- 官方教程:doc.rust-lang.org/book/ch03-02-dat...
本作品采用《CC 协议》,转载必须注明作者和本文链接