The Rust Programming Language
Rust
编程语言笔记。
起源:The Rust Programming Language Book。
装置
应用 rustup
来装置 Rust
。
Rust
源文件以 .rs
作为扩展名。
几个罕用的命令:
- 编译:
rustc .rs-file
- 运行:
./compiled-file
- 查看
Rust
编译器版本:rustc --version
- 查看
rustup
版本:rustup --version
- 更新
Rust
编译器:rustup update
- 卸载
Rust
和rustup
:rustup self uninstall
- 本地文档:
rustup doc
包管理工具
Rust 的包管理工具是 Cargo
。
几个罕用的命令:
- 查看
cargo
的版本:cargo --version
- 新建我的项目:
cargo new
- 我的项目构建:
cargo build
- 运行我的项目:
cargo run
- 我的项目查看:
cargo check
:该命令确保我的项目能够编译,但不生成可执行文件,速度比cargo build
更快
包
Rust
应用 TOML(Tom's Obvious Minimal Language)
格局来治理依赖。
应用 cargo new
创立新我的项目后,在该项目标目录下会有名为 Cargo.toml
的文件来治理依赖和包。
能够应用 cargo add
来增加依赖,也能够在 .toml
文件的 [dependencies]
字段下增加包名。
例如:
[dependencies]
rand = "0.8.5"
包的版本应用 三位的规范包规范。
在 .rs
文件中应用关键字 use
来导入包。
标准
Rust
的缩进采纳的是 4 个space
,而不是tab
Rust
应用 snake case 对变量和函数命名,也就是全副应用小写字母,单词两头应用下划线_
连贯,例如:var_name
Hello World
fn main() {println!("Hello, World!");
}
fn
是函数(function)的关键词main()
是 Rust 的主函数、相似于 C、C++- 每行完结须要用分号
;
示意
正文
Rust
有三种正文:
- 单行正文:
//
- 多行正文:
/* */
- 文档(DocString)正文:
/** */
变量
Rust
是 动态 类型语言,在申明变量时须要应用关键词 let
并在冒号 :
后指明变量的类型。这点相似于 Python
的 Type-Hint 以及 TypeScript
。
let var: u8 = 0;
可修改性
Rust
中的所有变量都有可批改(mutable)或不可修改性(immutable),如果在申明变量时不明确指明,那么默认为不可批改。
应用关键字 mut
示意变量能够批改。
let mut var: u8 = 2;
u8 = 3; // That's OK
let ano_var: u8 = 2;
u8 = 3; // Error
shadowing
fn main() {
let x: u32 = 5;
let x = x + 1;
{
let x = x * 2;
println!("The inner x: {x}");
}
println!("The outer x: {x}");
}
// The inner x: 12
// The outer x: 6
如上述代码所示:申明了多个名为 x
的变量,在 Rust
中,咱们称 第一个 x
被第二个 x
shadow,或者 第二个 x
overshadow 了第一个 x
,这意味着:当应用 x
这个变量时,编译器总是应用第二个 x
,即第二个 x
拿走了第一个 x
的所有,直到程序流来到第二个 x
的作用域或者第二个 x
也被 shadow。
shadow 和 mut 的区别
-
shadow 使得能够扭转同名变量的类型,然而
mut
会在编译时出错fn main() { let x: &str = " "; let x: usize = x.len(); // 5 let mut x: &str = " "; x = x.len() // Error}
-
shadow 使得能够批改不可批改的同名变量的值
fn main() { let x: u32 = 5; x = 6; // Error, 因为没有变量默认是不可批改的 let x: u32 = 5; let x = 6; println!("{}", x) // 6 }
常量
Rust
应用 const
关键字申明常量。通常来说,须要用大写字母申明常量。
const THE_DAY_I_START_LEARNING_RUST: String = "2023.5.9";
不可批改的变量和常量的区别在于:
- 常量只能是不可批改的,不能通过
mut
关键字使得常亮能够批改 - 常量通常只赋值给常量申明的表达式,而不是运行时的计算表达式
- 常量能够在任何作用域(scope)中申明,在程序运行期间,在其申明的作用域中是无效的
数据类型
Rust
是动态类型语言,因而在编译时就须要晓得所有的变量类型。
例如在数据转换中:
fn main() {let var = "100".parse().expect("Not a number!"); // Error
let var: u32 = "100".parse().expect("Not a number"); // OK, var == 100
}
根本类型
Rust
的根本数据类型有 4 种:
- 布尔 bool
- 整型 integer
- 浮点型 float
- 字符型 char
布尔型
布尔型有两个值:
- true
- false
整型
整型有 6 种长度,每种长度分类 有符号 和无符号 两类。
长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
整型字面量(literal)
字面量 | 举例 |
---|---|
十进制 | 98_222 |
十六进制 | 0xff |
八进制 | 0o77 |
二进制 | 0b1111_0000 |
字节(u8) | b’A’ |
- 整型的默认类型为
i32
- 在应用汇合类数据类型的索引时,应用
usize
或isize
浮点型
浮点型有两类,而且都是有符号的:
f32
f64
:默认类型
字符型
字符型用 c
(character)标识。
复合类型
Rust
的复合类型包含:
- 元组
- 数组
元组
元组 tuple
:用括号 ()
申明,元组元素的数据类型能够 不同。
元组是 定长 的,一旦申明后就不能扭转大小。
let tup: (u32, f32, bool) = (1, 2.2, true);
和 Python
不同,Rust
中的元组能够应用 .
运算符来拜访。
let tup: (u32, f32, bool) = (1, 2.2, true);
println!("{}", tup.0); // 1
println!("{}", tup.2); // 2.2
println!("{}", tup.3); // true
数组
数组 array
: 用方括号 []
申明,数组元素的数据类型必须 雷同。
数组也是 定长 的。
let arr: [u8; 5] = [1, 2, 3, 4, 5];
;
的前后别离示意数组元素的类型和数组元素的个数。
能够应用索引 []
,拜访数组元素,因为数组以定长模式存储在栈中:
let first = arr[0];
管制
条件
用 if, else if, else
等关键字控制程序流。
Rust
的条件语句不须要外嵌圆括号 ()
,然而也不同于 Python 的 :
,条件执行体须要用花括号:{}
。
fn main() {
let var: u32 = 8;
if var > 0 {println!("{var} is greater than 0!");
} else if var < 0 {println!("{var} is less than 0!");
} else {println!("{var} is equal to 0!");
}
}
注:和 JavaScript
、Ruby
等语言不同,Rust
语言 不会 在条件判断时主动转换变量的类型,例如:
fn main() {
let var: bool = true;
if var == 0 {println!("You can't get there in Rust");
}
}
循环
Rust
中有 3 种循环:
- 有限循环
loop
while
循环for
循环
完结、跳出循环的关键字:
break
跳出以后循环continue
完结本次循环(开始下一次循环)
loop 循环
Rust 能够应用关键字 loop
来创立有限循环,例如:
loop {println!("This is a infinite loop");
}
// 等价于
while true {println!("This is a infinite loop");
}
continue
对 loop
循环有效。
能够用 `name
给 loop
循环命名(标识符)以跳出多层循环,例如:
fn main() {
let mut count: u32 = 10;
`outer: loop {
let mut remaining: u32 = 2;
loop {println!("{}", count * remaining);
remaining -= 1;
if remaining == 0 {break outer;}
}
count -= 1;
println!("{}", count);
if count == 0 {break;}
}
}
while 循环
相似于其余语言的 while
循环。
同样,Rust
的循环条件语句不须要外嵌圆括号 ()
,然而也不同于 Python 的 :
,循环体须要用花括号:{}
。
fn main() {
let mut count = 10;
while count > 0 {println!("{}", count);
count -= 1;
}
}
for 循环
for in
for in
循环对遍历对象中的每一个元素都执行遍历:
fn main() {let arr: [u32; 5] = [1, 2, 3, 4, 5];
for element in arr {println!("{}", element);
}
}
for range
for range
相似于 Python
的同名函数。
fn main() {
for i in 0..5 {println!("{}", i);
}
}
应用 .rev()
倒序输入:
fn main() {for i in (0..5).rev() {println!("{}", i);
}
}
函数
应用关键字 fn
申明函数,Rust
总是 首先 执行 main
函数。
fn main() {
let var: u32 = 3;
increment_and_print(var);
}
fn increment_print(num: u32) -> u32 {
num += 1;
println!("{}", num);
return num;
// num
}
函数的参数须要申明名称和类型,返回值用 ->
示意,只须要申明类型。
能够应用关键字 return
显式返回值,也能够把返回值写在最初一行(不要应用 ;
结尾)。Rust
默认把最初一行的值作为返回值。
输出和输入
输出
应用规范库 std::io
来导入规范库的 io。
use std::io;
fn main() {let mut inp: String = String::new();
io::stdin.read_line(&mut inp).expect("Failed to read");
println!("{inp}");
}
- 应用
stdin
引入规范输出流, - 应用
read_line(&)
来读取输出, - 应用
expect()
来解决异常情况。
输入
应用 println!()
来输入内容。
println!()
示意调用 macro,println()
示意调用函数
Rust
不反对间接输入变量的值,必须 格式化(format)后输入。在引号 ""
中使花括号 {}
来输入变量。
fn main() {
let var: u32 = 15;
println!("{}", var); // 15
// println!("var equals {var}") Also ok!
// println!(var) Error!
}
构造体
Rust
的构造体相似于 C
,应用关键字 struct
申明。
构造体中的每个元素称为“域”(field),域是可批改的(mutable),应用 .
来拜访域的值。
struct User {
active: bool,
sign_in_count: u32,
username: String,
email: String
}
fn main() {
let user = User {
active: false,
sign_in_count: 1,
username: String::from("someusername"),
email: String::from("someuseremail"),
};
user1.email = "anotheremail";
}
能够应用 ..
来简化域成员的赋值:
struct User {
active: bool,
sign_in_count: u32,
username: String,
email: String
}
fn main() {
let user = User {
active: false,
sign_in_count: 1,
username: String::from("someusername"),
email: String::from("someuseremail"),
};
let user_2 = User {
active: true,
..user1
}
}
下面的代码示意,除了域 active
之外,user_2
的其余域值和 user
相等。
注:..user
后没有 ,
。
枚举
例如上面的代码:
use std::cmp::Ordering;
use std:io;
fn main() {println!("This is a guessing game");
const SECRET_NUMBER: u32 = 12;
let mut guess: String = String::new();
println!("Enter your guess:");
io::stdin.read_line(&mut guess).expect("Failed to read line");
let mut guess = match guess.parse().wrap() {Ok(num) => num,
Err(_) => {println!("You should enter a number!");
}
}
match guess.cmp::Ordering {Less => println!("Too small!"),
Greater => println!("Too big!"),
Equal => println!("You are the winner!");
}
}
match
关键字用于开始匹配枚举。
这段代码中用到了两个 枚举 类型,别离是:
- 对
guess
的类型判断会返回枚举类型Result
,它有Ok
和Err
两个枚举值,别离示意胜利和谬误两种状况 - 对
guess
和SECRET_NUMBER
两个值之间的比拟会返回枚举类型Ordering
,它有Less
、Greater
和Equal
三种状况,别离示意小于,大于和等于。
待续