Rust初识
Rust——一门赋予每个人构建可靠且高效软件能力的语言。
Rust编译器教你写代码!
为什么选择Rust?
- 高性能:速度惊人且内存利用率极高
- 可靠性:保证内存安全和线程安全,可以在编译期消除各种各样的错误。
- 生产力:出色的文档,友好的编译器和清晰的错误提示信息
安装Rust
以下皆以mac OS平台为主
1 |
|
Rust更新与卸载
1 |
|
使用Cargo
Cargo是Rust的构建系统和包管理器
Cargo创建项目
1 |
|
Cargo构建并运行项目
1 |
|
Rust编程概念
变量和可变性(Variables
)
变量默认是不可改变(immutable)的。
可通过变量前添加
mut
使变量可变。
1 |
|
常量(Const
)
常量在整个程序的生命周期中都有效,而且永不可变。
1 |
|
隐藏(Shadowing
)
可以定义一个与之前变量同名的新变量,此时第一个变量被第二个变量隐藏了,编译器只会看到第二个变量。
1 |
|
上述代码简单示例了Scope
及Shadowing
,此时进入{}
中,表示新开了个作用域(Scope),此时a
的逻辑仅在{}
有效,后续定义的let a = true;
表示之前的let a = sss
已被隐藏。
数据类型
每一个值都属于
数据类型
,必须明确每个值的数据类型,保证功能正常。
标量类型(Scalar Type)
代表一个单独的值。
整型(integers
)
默认为
i32
类型 | 示例 | |
---|---|---|
有符号整型(以i 开头)存储包含 -(2^(n-1)) ~ 2^(n-1) -1 之内的数字 |
i8 ,i16 ,i32 ,i64 ,i128 ,isize |
-10,0,1_000,123i64 |
无符号整型(以u 开头)存储包含 0 ~ 2^n -1 之内的数字 |
u8 ,u16 ,u32 ,u64 ,u128 ,usize |
0,123,10u16 |
其中isize
,usize
依赖运行程序的计算机架构:64位架构上则为64位,32位架构则为32位。
整型溢出:定义的数据类型,无法承载所设置的值。
系统默认处理方式:比此类型能容纳的最大值还大的值会绕到最小值,例如定义
u8
最大为256,设置值为256
,则输出的值为0
。
1 |
|
浮点型(floating-point)
默认为
f64
类型 | 示例 | |
---|---|---|
浮点型 | f32 ,f64 |
3.14,2f32 |
参考运算符可以使用所有数字类型进行运算。
1 |
|
布尔型(bool)
类型 | 示例 | |
---|---|---|
布尔型 | bool |
true ,false |
1 |
|
字符型(char)
类型 | 示例 | |
---|---|---|
字符型 | char |
‘a’,’ℤ’,’😻’ |
使用''
声明char
字面量。
1 |
|
字符串类型(String)
类型 | 示例 | |
---|---|---|
字符串型 | &str |
“wxy” |
1 |
|
复合类型(Compound Type)
将多个值组合成一个类型
元组类型(tuple)
将多个其他类型的值组合进一个复合类型的主要方式。
元组长度固定,一旦声明,长度不会增大或缩小。
类型 | 示例 | |
---|---|---|
元组类型 | () ,(T) ,(T1,T2) 其中T表示具体数据类型,例如 (i32, f64, u8) |
(123),(500, 6.4, 1) |
使用包含在()
中的,
分割的值列表来创建一个元组,每一个位置都有一个对应的类型。
1 |
|
单元元组
()
:不带任何值的元组,表示空值或空的返回类型。
可类比Java中的void
数组类型(array)
数组中每个元素的类型必须相同。
数组长度是固定的。
类型 | 示例 | |
---|---|---|
数组类型 | [T;N] 其中T表示具体数据类型,N表示数组个数,例如 (i32;5) |
[0;3],[1,2,3,4,5] |
存在两种写法
1 |
|
与其他语言访问数组元素方法一致
1 |
|
数组的打印方式与一般类型打印方式不同
1 |
|
字符串(&str/String)
&str / &String
字符串字面量类型为
&str
。
&String
是String的borrow类型,可以看作&str
不可变的固定长度的字符串。
1 |
|
String
String
是定义在标准库中的类型,分配在堆
上,可以动态的增长。底层存储为动态字节数组
。String是 UTF-8编码的。
新建字符串
主要有如下方式
- String::new()
- String::from(“”)
- “”.to_string()
1
2
3
4
5
6
7
8
9fn main() {
// let mut s = String::new(); //新建一个空的String
let mut s = String::from(""); //从字符串创建String
// let mut s = "".to_string(); //同上
s.push_str("hello, world");
s.push('!');
assert_eq!(s, "hello, world!");
}
更新字符串
主要有如下方式
- push( ch: char)
- push_str(string: &str)
- +string:&str
- replace(string: &str)
- format!()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18fn main(){
let mut s2: String = String::from("Hello "); //Hello
s2.push('W'); //Hello W
s2.push_str("or"); //Hello Wor
s2+="ld"; //Hello World
s2 = s2.replace("W","w"); //Hello world
println!("s2: {s2}");
}
fn main1(){
let ss1 = String::from("tic");
let ss2 = String::from("toc");
let ss3 = String::from("toe");
let hh = format!("{ss1}-{ss2}-{ss3}");
println!("hh: {hh}"); //tic-toc-toe
}注意事项:
当使用
+
进行字符串拼接时,只能用String
与&str
进行拼接,并且此时的String
的所有权会在此过程中被move(后续所有权会介绍)1
2
3
4
5
6
7
8fn main() {
let s1 = String::from("hello,");
let s2 = String::from("world!");
let s3 = s1 + &s2; //需要使用& 将String转换为&str
assert_eq!(s3,"hello,world!");
println!("{}",s1); //报错 value borrowed here after move
println!("{}",s2);
}
索引字符串
例如
s[0]
在Rust下是无法使用的,主要由于底层为Vec<u8>
的封装,按照字节长度进行返回。想要实现索引功能,就需要依赖后面介绍的
Slice
相关,此处先写上示例代码1
2
3
4
5
6
7
8fn main() {
let s1 = String::from("hi,中国");
let h = s1[0..1]; // `h` 字符在 UTF-8 格式中只需要 1 个字节来表示
assert_eq!(h, "h");
let h1 = &s1[3..6];// `中` 字符在 UTF-8 格式中需要 3 个字节来表示
assert_eq!(h1, "中");
}
遍历字符串
按照字符(char)或字节(byte)对字符串进行便利
- chars:字符
- bytes:字节
1
2
3
4
5
6fn main() {
// 填空,打印出 "你好,世界" 中的每一个字符
for c in "你好,世界".chars() {
println!("{}", c)
}
}
&str与String相互转换
&str => String
1
2
3
4
5
6fn test_str_to_string() {
let a: &str = "Hello";
let b = a.to_string();
let c = String::from(a);
let d = a.to_owned();
}
String => &str
1
2
3
4
5
6
7fn test_string_to_str() {
let a = String::from("Hello");
let b = a.as_str();
let c = &a;
let d = &String::from("Hello");
}
&str与String的使用场景
如果只想要一个字符串的只读视图,或者作为一个函数的参数,首选
&str
如果想拥有所有权,或者修改字符串就使用
String
切片(Slice)
跟数组类似,但是切片的长度无法在编译期得知。
其他类型Slice
1 |
|
字符串Slice
1 |
|
语句&表达式
函数体由一系列的语句和一个可选的结尾表达式构成。
- 语句:执行一些操作但不返回值的指令
- 表达式:计算并产生一个值。
主要区分最后有无;
1 |
|
返回值
不对返回值命名,需要在
->
后声明返回值类型
1 |
|
流程控制(Control Flow
)
根据条件来决定是否执行某些代码。
if / while / for
主要就是一些if
,while
,for
,这些的使用方式与Java的一致,不做细节说明
1 |
|
loop
重复执行代码,直到某些条件停止(执行到
break
)
1 |
|
循环标签
如果存在多重嵌套循环,通过在循环上指定循环标签用于退出
1 |
|
模式匹配(Match)
match
将一个值与一系列的模式进行比较,并根据匹配的模式执行相应的代码。
功能类似Java的
when
1 |
|
matches
功能与
match
差不多,支持多条件匹配
1 |
|
if let
if let
属于match
的一种语法糖,简化了使用。只能匹配某一模式
1 |
|
常见集合
Vector
HashMap
参考资料
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!