【一天一门编程语言】Rust 语言程序设计极简教程
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
文章目录
Rust 语言程序设计极简教程
用 markdown 格式输出答案。 不少于3000字。细分到2级目录。
介绍
Rust 是一种系统编程语言由 Mozilla Foundation 开发旨在提高软件的安全性、可靠性和可移植性。它是一种垃圾回收语言但拥有像 C/C++ 那样的运行速度。Rust 同时支持多种编程范式比如函数式编程、面向对象编程、泛型编程等而且它还拥有着丰富的标准库可以提供大量的功能。
Rust 的特性有安全性、性能、可移植性和灵活性。Rust 的安全性源自它强大的类型系统它可以让你编写更可靠、安全的代码而不会像 C/C++ 那样更容易出错。Rust 的性能比其他高级语言更好因为它会生成机器码而不是字节码。Rust 的可移植性也比其他语言更好可以在几乎所有的操作系统上运行而且对各种平台都有很好的支持。Rust 的灵活性也很强它可以让你做出你想要的任何功能而不会被语言本身的限制所束缚。
总而言之Rust 是一种很棒的系统编程语言它的特性使得它成为一种很有前途的语言。
安装 Rust
要开始学习 Rust首先就需要安装 Rust。
Rust 的安装过程非常简单。只需要下载安装程序运行它然后一路点击“下一步”就可以完成安装了。
你也可以使用官方提供的脚本来安装脚本会自动检测你的操作系统然后安装最新版本的 Rust
# Linux
curl https://sh.rustup.rs -sSf | sh
# MacOS
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
# Windows
.\rustup-init.exe
安装完成后你可以通过运行 rustc --version
来检查你的 Rust 版本
rustc 1.43.0 (2aa4c46cf 2019-11-28)
Hello, World
现在你已经安装完 Rust接下来就可以开始你的 Rust 学习之旅了我们从最基本的“Hello, World”开始
fn main() {
println!("Hello, World!");
}
这段代码很简单它会打印出“Hello, World!”字符串。
首先我们声明了一个 main
函数这个函数是程序的入口程序从这里开始执行。然后我们使用 println!
宏来打印出“Hello, World!”字符串。
要运行这段代码首先需要将它编译成可执行文件
rustc main.rs
编译完成后我们就可以执行 main
这个可执行文件
./main
Hello, World!
基础语法
在了解 Rust 的基础语法之前首先要熟悉 Rust 的语法结构
fn main() {
// 代码
}
Rust 程序的最基本结构就是上面这样也就是程序从 main
函数开始然后执行 main
函数中的代码。
变量及数据类型
Rust 支持多种数据类型比如整型、浮点型、字符串型等。要声明一个变量只需要使用 let
关键字
let x = 5; // x 是一个整型
let y = 1.0; // y 是一个浮点型
let s = "Hello"; // s 是一个字符串
要注意的是Rust 中的变量是不可变的也就是说一旦声明了一个变量它的值就不可以改变
let x = 5;
x = 10; // 错误x 是不可变的
如果要声明一个可变的变量可以使用 mut
关键字
let mut x = 5;
x = 10; // 正确x 是可变的
控制结构
Rust 支持多种控制结构比如 if
、while
、for
等。
if
语句
if
语句用于判断一个条件是否成立如果成立则执行 if
语句块中的代码
let x = 5;
if x < 10 {
println!("x is less than 10");
}
上面的代码会判断 x
是否小于 10如果小于 10则会打印出“x is less than 10”字符串。
while
语句
while
语句用于重复执行一段代码直到某个条件不满足
let mut x = 5;
while x > 0 {
println!("x is {}", x);
x -= 1;
}
上面的代码会不断打印出 x
的值直到 x
的值小于等于 0 为止。
for
语句
for
语句用于遍历一个集合
let arr = [1, 2, 3, 4, 5];
for x in arr.iter() {
println!("x is {}", x);
}
上面的代码会依次打印出 arr
中的每一个元素。
函数
函数是一段可以重用的代码块它可以接受参数并返回结果
fn add(x: i32, y: i32) -> i32 {
x + y
}
let result = add(1, 2);
println!("1 + 2 = {}", result); // 1 + 2 = 3
上面的代码定义了一个 add
函数它接受两个 i32
类型的参数并返回一个 i32
类型的结果。
泛型
泛型是指在编译时为类型变量指定类型参数而不是在运行时指定参数。它允许程序员在不重复编写代码的情况下处理多种类型的数据。它是Rust语言的一种重要特性可以帮助程序员更好地管理复杂的类型系统提高代码的可重用性和可维护性。
泛型的语法
Rust使用angle brackets尖括号<>
来指定泛型参数泛型参数可以是任意类型可以是结构体、枚举、函数或者模块等类型。
比如
fn foo<T>(x: T) {
// ...
}
上面的代码表示定义了一个泛型函数foo接受一个类型参数T。
另外Rust还允许在定义泛型时指定类型参数的限制比如类型参数必须实现某一个特定的trait
fn foo<T: Display>(x: T) {
// ...
}
泛型的应用
泛型的使用可以让程序更加函数化可以取代类型转换减少代码重复。
比如一个简单的函数接受一个参数并返回此参数的类型
fn foo(x: i32) -> i32 {
x
}
如果需要支持多种类型比如f32、u32等就需要多次重复编写相同的代码
fn foo_i32(x: i32) -> i32 {
x
}
fn foo_f32(x: f32) -> f32 {
x
}
fn foo_u32(x: u32) -> u32 {
x
}
而使用泛型就可以用一次代码就支持多种类型
fn foo<T>(x: T) -> T {
x
}
这样当调用foo函数时只需指定参数的类型即可
let a = foo::<i32>(1);
let b = foo::<f32>(2.0);
let c = foo::<u32>(3);
另外使用泛型还可以将程序的逻辑和类型分离比如实现一个函数来求数组的最大值
fn max<T: PartialOrd>(arr: &[T]) -> &T {
let mut max = &arr[0];
for x in &arr[1..] {
if x > max {
max = x;
}
}
max
}
上面的代码可以支持任意类型的数组只要满足PartialOrd trait即可比如可以支持i32类型的数组
let arr = [1, 3, 5, 7];
let max = max(&arr);
assert_eq!(max, &7);
也可以支持字符串类型的数组
let arr = ["foo", "bar", "baz"];
let max = max(&arr);
assert_eq!(max, &"foo");
Trait
Trait是Rust语言中的一种重要概念类似于其他语言中的接口可以用来表示某一类型具有的能力。它可以提供公共的行为比如定义函数定义类型限制等。
Trait的定义
Trait是Rust语言中的一种重要概念类似于其他语言中的接口可以用来表示某一类型具有的能力。它可以提供公共的行为比如定义函数定义类型限制等。
Trait的定义使用trait关键字
trait Foo {
// trait定义
}
例如定义一个trait用来定义可以被转换为字符串的类型
trait ToString {
fn to_string(&self) -> String;
}
Trait的实现
Trait可以用来实现多态。比如定义一个函数接受一个参数并将其转换为字符串
fn to_string<T: ToString>(x: T) -> String {
x.to_string()
}
使用这个函数就可以将任意实现了ToString trait的类型转换为字符串
let a = 1;
let a_str = to_string(a);
assert_eq!(a_str, "1");
let b = "foo";
let b_str = to_string(b);
assert_eq!(b_str, "foo");
Trait的继承
Trait也可以继承比如定义一个新的trait继承ToString trait
trait ToStringPlus: ToString {
fn to_string_plus(&self) -> String;
}
这样实现ToStringPlus trait的类型就可以使用ToString trait定义的方法
impl ToStringPlus for i32 {
fn to_string_plus(&self) -> String {
format!("{} plus", self.to_string())
}
}
let a = 1;
let a_str = a.to_string_plus();
assert_eq!(a_str, "1 plus");
模式匹配
模式匹配是一种灵活的代码组织手段可以用来实现条件分支、枚举类型的判断等功能。它是Rust语言的一种重要特性可以提高代码的可读性、可维护性减少重复的代码。
模式匹配的语法
模式匹配使用match关键字来实现
match x {
// 一些模式 => 表达式
// ...
}
其中x是一个表达式用来匹配模式模式是一种特定结构用来匹配x的值表达式是每个模式匹配成功后执行的动作。
比如可以使用模式匹配来判断某个变量是否是某个值
let x = 1;
match x {
1 => println!("x is 1"),
_ => println!("x is not 1"),
}
上面的代码中x是一个表达式用来匹配模式1是一个模式表示x的值必须是1println!(“x is 1”)是模式匹配成功后执行的动作。
模式匹配的特性
模式匹配有一些特殊的特性比如可以使用枚举类型的模式判断
enum Color {
Red,
Green,
Blue,
}
let color = Color::Red;
match color {
Color::Red => println!("color is Red"),
Color::Green => println!("color is Green"),
Color::Blue => println!("color is Blue"),
}
上面的代码中模式Color::Red表示匹配Color枚举类型的Red值。
另外模式匹配还支持多种结构比如可以使用元组的模式判断
let point = (1, 2);
match point {
(0, 0) => println!("point is at origin"),
(x, 0) => println!("point is on x-axis, x = {}", x),
(0, y) => println!("point is on y-axis, y = {}", y),
(x, y) => println!("point is at ({}, {})", x, y),
}
上面的代码中模式(x, 0)表示匹配一个元组其第一个元素是任意值第二个元素是0。
Rust 语言模块和结构体
Rust是一种非常受欢迎的现代编程语言在许多领域特别是系统级编程它都表现出色。在 Rust 中结构体是一种用来描述数据的重要工具它可以让你将相关数据分组并执行复杂的操作。
什么是结构体
结构体是 Rust 中的一种数据类型它可以用来描述一组相关的数据项每一项数据都有一个名字和类型。它可以用来描述一组具有相同属性的对象比如学生、商品或者人类。
结构体的定义如下
struct Name {
// 成员变量
}
结构体可以定义成员变量比如
struct Student {
name: String,
age: u8,
grade: u8,
}
这里定义了一个名为 Student 的结构体它有三个成员变量name、age 和 grade。
实例化结构体
在 Rust 中你可以用定义的结构体来创建实例比如
let student1 = Student {
name: String::from("John"),
age: 20,
grade: 90,
};
let student2 = Student {
name: String::from("Jack"),
age: 18,
grade: 80,
};
这里我们创建了两个结构体实例分别命名为 student1 和 student2。
结构体的方法
结构体也可以定义方法这些方法可以对结构体的成员变量进行操作比如
impl Student {
fn set_grade(&mut self, grade: u8) {
self.grade = grade;
}
}
这里我们定义了一个名为 set_grade 的方法它接受一个 u8 类型的参数并将它设置为结构体中 grade 的值。
结构体的模式匹配
结构体也可以用于模式匹配比如
let grade = match student1 {
Student { grade, .. } => grade,
};
这里我们使用模式匹配来提取 student1 结构体中的 grade 变量。
结构体的作用
结构体在 Rust 中起着重要的作用它可以帮助你将相关的数据分组并执行复杂的操作。它可以用来描述一组具有相同属性的对象并可以定义方法对其进行操作还可以用于模式匹配。
Rust 语言智能指针
一、Rust 中什么是智能指针
Rust 中智能指针是一种引用类型它具有智能的引用计数和清理资源的能力。Rust 智能指针不仅可以指向堆内存中的内存块而且还可以指向栈中的内存块这种智能指针在使用时不需要手动释放内存而是在智能指针离开作用域时自动释放对应的内存块从而避免了内存泄漏的问题。
Rust 智能指针的特点是
- Rust 智能指针拥有和引用一样的语义因此可以直接将智能指针传递给函数作为参数。
- Rust 智能指针在使用时可以自动处理内存的释放而不需要手动释放。
- Rust 智能指针可以用于指向堆内存中的内存块也可以用于指向栈中的内存块。
二、Rust 中智能指针的种类
Rust 中智能指针的种类有
1. Rc
Rc<T>
可以称为"引用计数智能指针"是一种不可变智能指针可以允许多个所有者拥有同一块内存空间它的特点是
- 可以允许多个所有者拥有同一块内存空间但不能改变内存中的值。
- 在智能指针离开作用域时自动释放内存从而避免了内存泄漏的问题。
2. RefCell
RefCell<T>
可以称为"可变智能指针"是一种可变智能指针可以向多个所有者提供可变的内存空间它的特点是
- 可以允许多个所有者拥有同一块内存空间并可以改变内存中的值。
- 在智能指针离开作用域时自动释放内存从而避免了内存泄漏的问题。
3. Box
Box<T>
可以称为"普通智能指针"是一种普通的智能指针可以指向堆内存中的内存块它的特点是
- 可以指向堆内存中的内存块但不能指向栈中的内存块。
- 在智能指针离开作用域时自动释放内存从而避免了内存泄漏的问题。
三、Rust 智能指针的使用
1. Rc 的使用
Rc<T>
是 Rust 中不可变智能指针可以允许多个所有者拥有同一块内存空间它的使用方法如下
use std::rc::Rc;
fn main() {
let s1 = String::from("s1");
let s2 = Rc::new(s1);
println!("s2 is {}", s2);
}
以上代码中Rc::new()
函数用于创建一个 Rc<T>
智能指针它接受一个参数这个参数是一个可以被包装的类型并返回一个 Rc<T>
类型的智能指针。
2. RefCell 的使用
RefCell<T>
是 Rust 中可变智能指针可以向多个所有者提供可变的内存空间它的使用方法如下
use std::cell::RefCell;
fn main() {
let s1 = String::from("s1");
let s2 = RefCell::new(s1);
println!("s2 is {}", s2);
}
以上代码中RefCell::new()
函数用于创建一个 RefCell<T>
智能指针它接受一个参数这个参数是一个可以被包装的类型并返回一个 RefCell<T>
类型的智能指针。
3. Box 的使用
Box<T>
是 Rust 中普通的智能指针可以指向堆内存中的内存块它的使用方法如下
use std::boxed::Box;
fn main() {
let s1 = String::from("s1");
let s2 = Box::new(s1);
println!("s2 is {}", s2);
}
以上代码中Box::new()
函数用于创建一个 Box<T>
智能指针它接受一个参数这个参数是一个可以被包装的类型并返回一个 Box<T>
类型的智能指针。
四、Rust 智能指针的优缺点
优点
- Rust 智能指针可以自动处理内存的释放而不需要手动释放从而避免了内存泄漏的问题。
- Rust 智能指针可以用于指向堆内存中的内存块也可以用于指向栈中的内存块因此可以提高程序运行效率。
- Rust 智能指针具有智能的引用计数和清理资源的能力可以有效管理内存资源。
缺点
- Rust 智能指针使用不当会导致循环引用的问题从而造成内存泄漏。
- Rust 智能指针的使用可能会影响编译器的性能从而影响程序的运行效率。
Rust 语言异步编程代码实例
Rust 是一种现代编程语言具有高效的内存安全性以及几乎不会出现空指针问题的安全性以及其他诸多优点使它成为一种强大而先进的语言。此外Rust 语言还支持使用异步 API使编写异步程序变得更容易。
什么是异步编程
异步编程是一种编程模式它使程序可以在不同的时间段内执行不同的任务而不用等待前一个任务完成。这样可以提高程序的性能因为它可以在不同的时间段处理多个任务。
Rust 的异步编程实现
Rust 语言支持一种叫做“Future”的异步编程模式可以让我们在不阻塞应用程序的情况下异步地执行任务。我们可以使用 Rust 的 Future API 来实现异步编程它提供了一种高效和可靠的方式来编写异步代码。
使用 Future API 的示例
下面是一个使用 Rust 的 Future API 来实现异步编程的示例
use std::future::Future;
fn run_async<F>(f: F)
where
F: Future<Output = ()> + 'static,
{
// 创建一个新的线程来运行 Future
std::thread::spawn(|| f.await);
}
fn main() {
let future = async {
// 这里是异步任务的代码
};
run_async(future);
}
在上面的代码中我们使用 run_async
函数来异步地运行 future
变量该变量包含一个异步任务的代码。我们还可以将 run_async
函数用于任何其他的异步任务它可以让我们轻松地在多个线程上运行多个异步任务。
使用 async/await 语法
Rust 还支持 async/await 语法可以让编写异步程序变得更加简单。下面是一个使用 async/await 语法实现的异步示例
async fn run_async() {
// 这里是异步任务的代码
}
fn main() {
let future = run_async();
tokio::spawn(future);
}
在上面的代码中我们使用 run_async
函数异步地运行 future
变量它包含一个异步任务的代码。我们还可以使用 tokio::spawn
来轻松地运行多个异步任务。
小结
Rust 语言支持使用 Future API 和 async/await 语法来实现异步编程可以让我们在不阻塞应用程序的情况下异步地执行任务。这样可以提高程序的性能因为它可以在不同的时间段处理多个任务。
Rust 语言实现斐波那契数列代码实例循环与递归
1. 什么是斐波那契数列
斐波那契数列Fibonacci Sequence又称黄金分割数列指的是这样一个数列1、1、2、3、5、8、13、21、34、……
在数学上斐波纳契数列以如下被以递推的方法定义
F(1)=1F(2)=1, F(n)=F(n-1)+F(n-2)n>=3n∈N*
2. Rust 语言实现斐波那契数列的循环方法
Rust 语言实现斐波那契数列的循环方法主要采用for循环的方式具体实现如下
fn fibonacci_loop(n: u32) -> u32 {
let mut a = 0;
let mut b = 1;
for _ in 0..n {
let new_b = a + b;
a = b;
b = new_b;
}
a
}
上述代码中for循环采用了n次迭代每次迭代中我们都会计算出斐波那契数列中的下一个数并将其赋值给变量b最终得到的变量a即为所求的斐波那契数列的第n项。
3. Rust 语言实现斐波那契数列的递归方法
Rust 语言实现斐波那契数列的递归方法需要先定义一个函数其功能是计算斐波那契数列的每一项并以此作为基础递归实现斐波那契数列。具体代码如下
fn fibonacci_rec(n: u32) -> u32 {
if n == 0 {
return 0;
}
if n == 1 {
return 1;
}
fibonacci_rec(n-1) + fibonacci_rec(n-2)
}
上述代码中我们首先定义了一个函数其功能是计算斐波那契数列的每一项并以此作为基础递归实现斐波那契数列。在实现递归调用的过程中我们需要注意用到递归的函数必须要有终止条件也就是上述代码中的if n == 0和if n == 1这两个语句这两个语句的作用是作为终止条件当求解到n=0或n=1时就不再进行递归调用而是直接返回结果。最终得到的函数返回值即为所求斐波那契数列的第n项。