Rust
一门赋予每个人构建可靠且高效软件能力的语言
安装
官方下载网址:
安装 Rust - Rust 程序设计语言 一门赋予每个人构建可靠且高效软件能力的语言。https://www.rust-lang.org/zh-CN/tools/install安装 Rust 需要C++生成工具的支持,Visual Studio2017+版本以上都可以。
尝试
Rust Playground 官方在线编译器A browser interface to the Rust compiler to experiment with the languageicon-default.png?t=N3I4https://play.rust-lang.org/?version=stable&mode=debug&edition=2021
hello, world
1. fn main() { 2. println!("hello, world"); 3. }
创建一个后缀为 .rs 的源码文本文件 hello.rs,然后用Rust编译成一个可执行文件;也可以把源码直接粘贴到官方提供的在线编译器内执行。
为什么学习众多编程语言的第一个程序都是 hello, world ?
hello world 的起源
追溯到1972年,贝尔实验室著名研究员Brian Kernighan在撰写“B语言教程与指导(Tutorial Introduction to the Language B)”时初次使用(程序),这是目前已知最早的在计算机著作中将hello和world一起使用的记录。之后,在1978年,他在他和Dennis Ritchie合作撰写的C语言圣经“The C Programming Language”中,延用了“hello,world”句式,作为开篇第一个程序。在这个程序里,输出的”hello,world”全部是小写,没有感叹号,逗号后有一空格。虽然之后几乎没能流传下来这个最初的格式,但从此用hello world向世界打招呼成为惯例。几乎每一个程序设计语言的教材中的第一个范例都是hello world程序,因此在学习一门新语言的时候用hello world作为起步已经成为计算机程序界的一个传统。
编译
在cmd窗口下,把源码文件 hello.rs 编译,然后执行。
1. D:\Rust\hello>rustc hello.rs 2. 3. D:\Rust\hello>hello 4. hello, world
链接出错
当编译发生以下报错时,说明生成工具没有安装成功
D:\Rust\hello\src>rustc main.rs error: linker `link.exe` not found | = note: program not found note: the msvc targets depend on the msvc linker but `link.exe` was not found note: please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. note: VS Code is a different product, and is not sufficient. error: aborting due to previous error
执行以下2条命令进行修复
1. D:\Rust\hello>rustup toolchain install stable-x86_64-pc-windows-gnu 2. 3. D:\Rust\hello>rustup default stable-x86_64-pc-windows-gnu
官方教程
官方网站网提供了2本基础教程以及众多文档,入门零成本,基本用不上买纸质书,省钱。
《Rust 程序设计语言》
被亲切地称为“圣经”。本书从基础出发,给出了 Rust 语言的概览。您将在阅读本书的过程中构建几个项目,读完本书后,您就能扎实地掌握 Rust 语言。
https://doc.rust-lang.org/book/
《通过例子学 Rust》
如果您不喜欢阅读大量的文档来学习语言,那么此书就能涵盖您要学的知识。虽然本书花了很多篇幅来解释代码,但它展示的代码很丰富,并且尽量减少了文字解释。它还包括很多练习!
https://doc.rust-lang.org/rust-by-example/
核心文档
以下所有文档都可以用 rustup doc 命令在本地阅读,它会在您的浏览器中离线打开这些资源!
标准库
版本指南
Rust 版本指南。
CARGO 手册
Rust 的包管理器和构建系统。
RUSTDOC 手册
学习如何为您的 crate 编写完美的文档。
RUSTC 手册
熟悉 Rust 编译器中可用的选项。
编译错误索引表
深入解释了您可能会遇到的编译错误。
有编程基础的大概浏览一遍,很快就能上手了
语法基础
变量和数据类型
在 Rust 中,变量可以通过 let
关键字进行声明和初始化。例如:
1. let x = 5; 2. let y: i32 = 10;
第一行代码定义了一个名为 x 的变量,其类型为 Rust 推断得到的整数类型。第二行代码定义了一个名为 y 的变量,并明确指定其类型为 i32 整数类型。
Rust 中的数据类型包括数字、字符、布尔值、字符串等。其中,数字类型包括整数和浮点数,可以用 i8、i16、i32、i64、u8、u16、u32、u64、f32、f64 等类型进行声明。而布尔值则用 bool 表示,取值为 true 或 false。字符类型用 char 表示,由单引号包围,例如:
let c = 'C';
字符串类型用双引号包围,可以是非 ASCII 字符串,例如:
let s = "Hello, 世界!";
注意:let mut
变量赋值
let
和 let mut
声明变量时的区别在于后者声明的变量可变,而前者声明的变量为不可变。let
声明的变量不能再次被赋值,而 let mut
声明的变量可以被修改赋值。
复合数据结构
元组 (Tuple)
元组是将多个不同类型的值组合在一起形成一个新的复合类型。元组使用圆括号 ()
来定义,元素之间使用逗号 ,
隔开。元组可以通过模式匹配来解构。例如:
let person: (String, usize, f64) = (String::from("Alice"), 30, 6.0); println!("{} is {} years old and {} feet tall.", person.0, person.1, person.2);
数组 (Array)
数组是由同一类元素组成的数据集合。数组的长度在编译时就已经确定,不可改变。数组使用中括号 []
来定义。例如:
let numbers: [i32; 5] = [1, 2, 3, 4, 5]; println!("The third element is {}.", numbers[2]);
向量 (Vector)
向量是一种动态数组类型,可以在运行时动态地增加或减少其大小。Vector 可以存储任意类型的数据,并且支持快速随机访问元素、在末尾追加元素、在任意位置插入和删除元素等操作。Vector 使用 Vec 类型来创建,例如:
let mut numbers: Vec<i32> = vec![1, 2, 3, 4, 5]; // 访问某个元素 println!("The third element is {}.", numbers[2]); // 在末尾追加元素 numbers.push(6); // 插入元素到特定位置 numbers.insert(3, 10); // 删除特定位置的元素 numbers.remove(2); // 遍历所有元素 for num in &numbers { println!("{}", num); }
集合 (Set)
集合类型存储一组唯一的、无序的元素。Set 具有高效地判定元素是否存在的功能,但是不支持对元素的随机访问和插入。Set 使用 HashSet 类型来创建,例如:
use std::collections::HashSet; let mut colors = HashSet::new(); // 插入元素 colors.insert(String::from("red")); colors.insert(String::from("green")); colors.insert(String::from("blue")); // 判断元素是否存在 if colors.contains("red") { println!("The set contains red."); } // 删除元素 colors.remove("green"); // 遍历所有元素 for color in &colors { println!("{}", color); }
结构体 (Struct)
结构体是一种自定义类型,可以包含不同类型的字段。通过在结构体中定义多个字段,可以将它们组合成一个单独的数据类型。结构体使用 struct
关键字来定义,字段可以是不同的类型,并且也可以包含其他的结构体。例如:
struct Person { name: String, age: usize, height: f64, } let alice = Person { name: String::from("Alice"), age: 30, height: 6.0, }; println!("{} is {} years old and {} feet tall.", alice.name, alice.age, alice.height);
关键字
as const else enum extern false fn for if impl in let loop match mod move mut pub ref return Self self static struct super trait true type unsafe use where while abstract become box do final macro override priv typeof unsized virtual yield
这些关键字具有不同的含义和用法,例如:
fn: 声明一个函数
let: 声明一个变量
if、else、for、while 等: 分别表示条件语句、循环语句
match: 匹配表达式的值与模式
mod、use: 分别表示模块声明与模块引用
struct、enum、trait、impl 等: 分别表示结构体、枚举类型、特质、实现等
在 Rust 中,使用这些关键字需要注意避免与现有标识符冲突。如果需要使用与关键字同名的标识符,则可以使用反引号 将标识符括起来,例如:
let `match` = 3; println!("the value of match is {}", `match`);
以上代码中,用反引号括起来的 match
可以作为变量名使用,但是不推荐这么做,因为会让代码不够清晰。
控制语句
Rust 支持常见的控制流语句,包括条件语句、循环语句和匹配语句等。
条件语句
用 if
和 else
关键字表示,例如:
let x = 10; if x < 0 { println!("x is negative"); } else if x > 0 { println!("x is positive"); } else { println!("x is zero"); }
循环语句
用 loop
、while
和 for
关键字表示,例如:
let mut x = 0; loop { x += 1; if x == 10 { break; } } println!("x is {}", x); let mut y = 0; while y < 10 { y += 1; } println!("y is {}", y); let a = [1, 2, 3, 4, 5]; for element in a.iter() { println!("element is {}", element); }
匹配语句
用 match
关键字表示,可以根据不同的值匹配执行不同的代码块。例如:
let x = 5; match x { 1 => println!("x is one"), 2 | 3 | 4 => println!("x is two or three or four"), // 匹配任何其他数字 _ => println!("x is {}", x), }
函数
Rust 中的函数可以通过 fn
关键字进行定义,例如:
fn add(x: i32, y: i32) -> i32 { x + y } fn main() { let a = add(1, 2); let b = add(2, 3); println!("{}\n{}", a, b); }
该函数接受两个 i32
参数 x
和 y
,返回它们的和。
函数的最后一个表达式被视为返回值,这与其它大多数语言不同:可以省去 return 关键字。
Rust 支持函数的默认参数和可变参数,例如:
fn mul(x: i32, y: i32, z: i32) -> i32 { return x * y * z } fn div(x: f32, y: f32) -> f32 { if y == 0.0 { panic!("division by zero"); } return x / y } fn print(words: &str, times: i32) { for _ in 0..times { println!("{}", words); } } fn main() { let a = mul(1, 2, 3); let b = div(10.0, 3.0); let c = "hello"; println!("{}\n{}", a, b); print(c, 3); }
Rust 也支持泛型类型参数,例如:
fn add<T: std::ops::Add<Output=T>>(x: T, y: T) -> T { x + y } fn foo<T>(x: T) -> T { x } fn main() { let a = add(1, 2); let b = add(2.0, 3.0); println!("{}\n{}\n", a, b); let a = foo(1); // a 为整数类型 let b = foo("hello"); // b 是字符串类型 let c = foo(vec![1, 2, 3]); // c 是一个整数向量类型 println!("{}\n{}\n{:?}", a, b, c); }
模块
模块是 Rust 中的一种隔离和组织代码的方式,其可以分为本地模块和外部模块。本地模块用 mod
关键字表示,用于组织和封装代码,例如:
mod math { fn add(x: i32, y: i32) -> i32 { x + y } pub fn sub(x: i32, y: i32) -> i32 { x - y } }
该代码中,定义了一个 math 模块和其中的两个函数 add 和 sub。其中,函数 add 是私有的,只能在模块内部使用,而函数 sub 是公有的,可以在其他模块中使用。
除了本地模块之外,Rust 还支持使用 extern crate 加载外部依赖库,并通过 use 关键字引用其模块、类型和函数等。例如:
extern crate rand; use rand::Rng; fn main() { let mut rng = rand::thread_rng(); let n: i32 = rng.gen_range(1, 7); println!("the random number is: {}", n); }
以上就是 Rust 语言的基础语法介绍,包括变量和数据类型、控制流、函数和模块等内容。Rust 相比于其他语言,具有更加严格的类型检查和所有权规则等特性,可以保证代码的内存安全和高效运行。
代码实例
1. 两数之和
use std::collections::HashMap; fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> { let mut map = HashMap::new(); for (i, &num) in nums.iter().enumerate() { if let Some(&j) = map.get(&(target - num)) { return vec![j as i32, i as i32]; } map.insert(num, i); } vec![] } fn main() { let nums = vec![2, 7, 11, 15]; let target = 9; let result = two_sum(nums, target); println!("{:?}", result); // 输出 [0, 1] }
2. 最长子串
pub fn length_of_longest_substring(s: String) -> i32 { let mut chars = s.chars(); let mut map = std::collections::HashMap::new(); let mut max_length = 0; let mut start = 0; let mut end = 0; while let Some(c) = chars.next() { if let Some(index) = map.get(&c) { start = start.max(*index + 1); } end += 1; map.insert(c, end - 1); max_length = max_length.max(end - start); } max_length as i32 } fn main() { let s = String::from("abcabcbb"); let result = length_of_longest_substring(s); println!("{}", result); let s = String::from("bbbbb"); let result = length_of_longest_substring(s); println!("{}", result); let s = String::from("pwwkew"); let result = length_of_longest_substring(s); println!("{}", result); }
3. 反转整数
pub fn reverse(x: i32) -> i32 { let mut x = x; let mut res = 0; while x != 0 { let pop = x % 10; x /= 10; if res > std::i32::MAX / 10 || (res == std::i32::MAX / 10 && pop > 7) { return 0; } if res < std::i32::MIN / 10 || (res == std::i32::MIN / 10 && pop < -8) { return 0; } res = res * 10 + pop; } res } fn main() { let x = 123; println!("{}", reverse(x)); let x = -123; println!("{}", reverse(x)); let x = 120; println!("{}", reverse(x)); }
2023.5.3