当前位置:首页 > 科技  > 软件

一网打尽 Rust 语法

来源: 责编: 时间:2024-04-26 08:51:50 16观看
导读1. 构建运行环境我们在Rust环境配置和入门指南中详细介绍了如何安装Rust环境构建一个Rust应用编译和运行的区别使用Cargo构建Rust应用下面,我们就之间直入主题了。通过创建一个名为 main.rs 的文件并将以下代码放入其

1. 构建运行环境

我们在Rust环境配置和入门指南中详细介绍了v0R28资讯网——每日最新资讯28at.com

  • 如何安装Rust环境
  • 构建一个Rust应用
  • 编译和运行的区别
  • 使用Cargo构建Rust应用

下面,我们就之间直入主题了。v0R28资讯网——每日最新资讯28at.com

通过创建一个名为 main.rs 的文件并将以下代码放入其中来编写我们的第一个 Rust 代码:v0R28资讯网——每日最新资讯28at.com

fn main() {    println!("Hello, Front789!");}

然后通过运行 rustc main.rs 和 ./main.exe 来运行这个程序,就像运行 C 程序一样。v0R28资讯网——每日最新资讯28at.com

Cargo 是 Rust 的构建系统和包管理器v0R28资讯网——每日最新资讯28at.com

我们也可以使用 cargo 创建项目。v0R28资讯网——每日最新资讯28at.com

  • cargo new hello_cargo:初始化一个新项目。
  • cargo build:构建一个 cargo 项目。
  • cargo run:运行一个 cargo 项目,这将编译并运行代码。
  • cargo check:检查是否有编译错误,它比cargo build速度更快。
  • cargo build --release:这将使用优化进行编译,用于最终生产构建。

2. 变量类型

在 Rust 中,默认情况下「变量是不可变」的,这意味着一旦给变量赋值,其值就不会改变。v0R28资讯网——每日最新资讯28at.com

所以如果想要一个可变的,即可改变的值,使用 mut。v0R28资讯网——每日最新资讯28at.com

let a = 5;let mut b = 5; // 可变的
  • 整数:有各种大小的有符号和无符号整数(例如,i8、i16、i32、i64、u8、u16、u32、u64)

图片图片v0R28资讯网——每日最新资讯28at.com

let number: i32 = 42;
  • 浮点数:单精度和双精度浮点数(例如,f32、f64)

图片图片v0R28资讯网——每日最新资讯28at.com

let pi: f64 = 3.14159;
  • 布尔值:Rust的布尔类型只拥有两个可能的值true和false,它「只会占据单个字节的空间大小」。使用bool来表示一个布尔类型。
let is_rust_cool: bool = true;
  • 字符:在Rust中char类型「占4字节」,是一个Unicode标量值,这意味着它可以表示比ASCII多的字符内容。使用char 类型表示一个字符类型
let heart_emoji: char = '❤';
  • 字符串:可变字符串

图片图片v0R28资讯网——每日最新资讯28at.com

let mut s = String::from("front789");
  • 字符串切片:不可变且借用的字符串切片
let s1: &str = "front789";
  • 数组:数组中每一个元素都必须是「相同类型」。 Rust中「数组拥有固定的长度,一旦声明就再也不能随意更改大小」
let array: [i32; 3] = [1, 2, 3];let a = [3; 5]; // 用值 3 初始化大小为 5 的数组
  • 元组

图片图片v0R28资讯网——每日最新资讯28at.com

为了从元组中获得单个的值,可以使用「模式匹配」来解构元组v0R28资讯网——每日最新资讯28at.com

还可以通过「索引」并使用点号(.)来访问元组中的值v0R28资讯网——每日最新资讯28at.com

let tup = (500, 6.4, 1);let (x, y, z) = tup;let aa = tup.0; // 引用元组中的第一个项目
  • 向量

图片图片v0R28资讯网——每日最新资讯28at.com

  • 指针和引用

指针是一个变量,它存储了一个值的「内存地址」v0R28资讯网——每日最新资讯28at.com

Rust 中最常见的指针是引用。引用以 & 符号为标志并「借用了它们所指向的值」。除了引用数据没有任何其他特殊功能。它们也没有任何额外开销,所以应用得最多。v0R28资讯网——每日最新资讯28at.com

fn main() {    // 标量类型    let number: i32 = 42;    let pi: f64 = 3.14159;    let is_rust_cool: bool = true;    let heart_emoji: char = '❤';    // 复合类型    let array: [i32; 3] = [1, 2, 3];    let tuple: (i32, f64, char) = (10, 3.14, 'a');    let slice: &[i32] = &[1, 2, 3];    let string: String = String::from("Hello, Front789!");    let string_slice: &str = "Hello, Front789!";    // 特殊类型    let reference_to_number: &i32 = &number;    let optional_value: Option<i32> = Some(42);    let result_value: Result<i32, &str> = Ok(42);}

以上内容就是Rust中所涉及到的各种数据类型,我们可以从以下的链接中找到更为详细的解释v0R28资讯网——每日最新资讯28at.com

  • 基础概念
  • 集合
  • 智能指针

3. 操作数组

不可变数组:

不可变数组在 Rust 中用 [T; N] 语法来声明,其中 T 表示数组元素的类型,而 N 表示数组的长度。v0R28资讯网——每日最新资讯28at.com

对于不可变数组,我们可以使用下标访问其元素,但不能修改元素的值。v0R28资讯网——每日最新资讯28at.com

let array = [1, 2, 3, 4, 5];let first_element = array[0]; // 访问第一个元素arr[0] = 6; // 这行代码会导致编译错误,因为数组是不可变的// 迭代// 使用 for 循环for &num in &array {    println!("{}", num);}// 另一种迭代器array.iter().for_each(|&num| {    println!("{}", num);});let slice = &array[1..3]; // 从索引 1 到索引 2(包括)切片

可变数组

Vec<T> 是 Rust 中可变长数组的实现,它允许您动态地增加或减少数组的大小。v0R28资讯网——每日最新资讯28at.com

let mut array = [1, 2, 3, 4, 5];array[0] = 10; // 修改第一个元素let mut vec = Vec::new(); // 创建一个空 Vecvec.push(1); // 向 Vec 中添加一个元素vec.push(2);vec.push(3);// 使用 iter() 遍历元素for item in array.iter() {    println!("{}", item);}// iter_mut() 方法返回一个可变的迭代器,允许修改 Vec 中的元素for item in array.iter_mut() {    *item += 1; // 对每个元素加 1}// maplet doubled_array: Vec<_> =     array.iter()    .map(|&num| num * 2)    .collect();// filterlet even_elements: Vec<_> =     array.iter()    .filter(|&&num| num % 2 == 0)    .collect();// len() 方法返回 Vec 中元素的数量array.len()// remove() 方法移除指定索引位置的元素,并返回该元素。如果索引越界,它将导致 panic。let removed_item = array.remove(2) // removed_item 为3

4. 操作字符串

let s1 = String::from("Hello, ");let s2 = String::from("Front789!");let combined = s1 + &s2; // 注意:s1 在这里被移动,之后不能再使用println!("{}", combined); // 打印 "Hello, Front789!"let mut s = String::from("Hello, ");s.push_str("Front789!");println!("{}", s); // 打印 "Hello, Front789!"// 获取字符let s = String::from("hello");let first_char = s.chars().nth(0); // 访问第一个字符// 子字符串let s = String::from("hello Front789");let substring = &s[0..5]; // 提取 "hello"// len()let s = String::from("hello");let length = s.len(); // 字符串的长度// replacelet s = String::from("hello");let replaced = s.replace("l", "z"); // 替换 "l" 为 "z"// splitlet s = String::from("hello Front789");let words: Vec<&str> = s.split_whitespace().collect(); // 分割成单词// 转换 &str 和 Stringlet s = String::from("hello");let s_ref: &str = &s; // 将 String 转换为 &strlet s_copy: String = s_ref.into(); // 将 &str 转换为 String

5. 操作向量

let mut v1 = vec![1, 2, 3]; // 使用 vec![] 宏let mut v2: Vec<i32> = Vec::new(); // 使用 Vec::new() 构造函数let mut v = Vec::new();v.push(1);v.push(2);let first_element = v[0]; // 访问第一个元素// 迭代// 使用 for 循环for num in &v {    println!("{}", num);}// 使用迭代器v.iter().for_each(|&num| {    println!("{}", num);});// slicelet slice = &v[1..3]; // 从索引 1 到索引 2(包括)提取元素// removelet removed_element = v.remove(1); // 移除索引为 1 的元素(返回被移除的元素)// sort()v.sort();// joinlet tt= vec!["hello", "Front789"];let joined_string = tt.join(", "); // 使用逗号和空格连接元素

6. 函数

Rust代码使用「蛇形命名法」来作为规范函数和变量名称的风格。蛇形命名法「只使用小写的字母进行命名,并以下画线分隔单词」。v0R28资讯网——每日最新资讯28at.com

  • 参数,它们是一种「特殊的变量,并被视作函数签名的一部分」。当函数存在参数时,你需要在「调用函数时为这些变量提供具体的值」
  • 在Rust中,「函数的返回值等同于函数体的最后一个表达式」。

语法

fn 函数名(参数1: 类型1, 参数2: 类型2) -> 返回类型 {    // 函数体    // 可选的表达式}

最后一行返回值时不需要调用 return。v0R28资讯网——每日最新资讯28at.com

fn add_numbers(x: i32, y: i32) -> i32 {    let sum = x + y;    sum // 函数中的最后一个表达式会隐式返回}

如果想要一个无返回值的函数,不要定义返回类型。v0R28资讯网——每日最新资讯28at.com

我们可以在基础概念_函数部分查看更详细的解释v0R28资讯网——每日最新资讯28at.com

7. 输入/输出

输入

要读取一个值,使用 io stdin 并给出变量的值,在失败时需要提供 expect 消息,否则会出错。v0R28资讯网——每日最新资讯28at.com

let mut guess = String::new();    io::stdin().read_line(&mut guess).expect("该行读取失败");

输出 / 打印

println!("输出对应的变量信息 {}", guess); // 这里的 guess 是变量名。

你也可以在末尾有变量v0R28资讯网——每日最新资讯28at.com

let y = 10;println!("y + 2 = {}", y + 2);

8. Shadowing

在Rust中,一个「新的声明变量可以覆盖掉旧的同名变量」,我们把这一个现象描述为:「第一个变量被第二个变量遮蔽Shadow了」。这意味着随后使用这个名称时,它指向的将会是第二个变量。v0R28资讯网——每日最新资讯28at.com

fn main() {    let x = 5; // 定义值为 5 的变量 x    println!("原始值 x: {}", x); // 打印 "原始值 x: 5"        let x = 10; // Shadowing:定义一个新的值为 10 的变量 x    println!("Shadowed x: {}", x); // 打印 "Shadowed x: 10"}

图片图片v0R28资讯网——每日最新资讯28at.com

9. 控制块

图片图片v0R28资讯网——每日最新资讯28at.com

If else

if condition1 {    // 如果 condition1 为真,则执行的代码} else if condition2 {    // 如果 condition2 为真,则执行的代码} else {    // 如果 condition1 和 condition2 都为假,则执行的代码}

10. 循环

Rust提供了3种循环v0R28资讯网——每日最新资讯28at.com

  • loop
  • while
  • for

loop

loop {    println!("永无止境的执行");}

While 循环

let mut count = 0;while count < 5 {    println!("Count: {}", count);    count += 1;}

For 循环

for i in 0..5 {    println!("{}", i);}

foreach

当然也少不了对数值的遍历操作。v0R28资讯网——每日最新资讯28at.com

(1..=5).for_each(|num| {    println!("Number: {}", num);});// Number: 1// Number: 2// Number: 3// Number: 4// Number: 5

..:它表示一个扩展运算符,表示从第一个数字到最后一个数字生成。v0R28资讯网——每日最新资讯28at.com

我们也可以在循环中使用 continue 和 break。v0R28资讯网——每日最新资讯28at.com

11. 所有权

图片图片v0R28资讯网——每日最新资讯28at.com

这个概念是需要特别注意和反复观看的部分。v0R28资讯网——每日最新资讯28at.com

MOVE(或)重新分配变量

当变量值被重新分配时,值会给新的所有者,并且旧的所有者被丢弃。v0R28资讯网——每日最新资讯28at.com

这种行为在字符串中经常看到,而不是其他类型,如下所示:v0R28资讯网——每日最新资讯28at.com

let s1 = String::from("hello");let s2 = s1;println!("{}, world!", s1);

这将导致错误,因为 s1 在 s2=s1 之后不再有效。v0R28资讯网——每日最新资讯28at.com

如何解决上面的问题呢,我们可以使用 Clone:v0R28资讯网——每日最新资讯28at.com

let s1 = String::from("hello");let s2 = s1.clone();println!("s1 = {}, s2 = {}", s1, s2);

某些类型隐式实现了 Clone。v0R28资讯网——每日最新资讯28at.com

let x = 5; // x 拥有整数 5let y = x; // 将 x 的值复制到 y,不传递所有权

例如,整数隐式实现了 Clone,因此这段代码不会报错。v0R28资讯网——每日最新资讯28at.com

图片图片v0R28资讯网——每日最新资讯28at.com

所有权和函数

fn main() {    let s = String::from("hello");  // s 进入作用域    takes_ownership(s);             // s 的值移动进入函数...                                    // ... 所以这里不再有效    let x = 5;                      // x 进入作用域    makes_copy(x);                  // x 会移入函数,                                    // 但 i32 是 Copy,所以在之后继续使用 x 是可以的} // 在这里,x 超出作用域,然后是 s。但因为 s 的值被移动了,所以没有什么特别的发生。fn takes_ownership(some_string: String) { // some_string 进入作用域    println!("{}", some_string);} // 在这里,some_string 超出作用域,调用 drop。内存被释放。fn makes_copy(some_integer: i32) { // some_integer 进入作用域    println!("{}", some_integer);} // 在这里,some_integer 超出作用域。没有什么特别的发生。

如果我们像在变量被移动后,继续使用,那么我们就使用 takes_ownership(s.clone()); (或者)在 takes_ownership 函数中返回值,像这样:v0R28资讯网——每日最新资讯28at.com

fn main() {    let s2 = String::from("hello");     // s2 进入作用域    let s3 = takes_and_gives_back(s2);  // s2 移入并被返回}fn takes_and_gives_back(a_string: String) -> String {     a_string  // 返回并移出到调用函数}

借用 — 所有权

传递变量的引用,所有权不会被传递。v0R28资讯网——每日最新资讯28at.com

我们称「创建引用的操作为借用」。就像现实生活中,如果一个人拥有一样东西,你可以从他们那里借来。借了之后,你必须归还。你不拥有它。v0R28资讯网——每日最新资讯28at.com

fn main() {    let s1 = String::from("hello");    let len = calculate_length(&s1);    println!("The length of '{}' is {}.", s1, len);}fn calculate_length(s: &String) -> usize {    s.len()}

针对此处更详细的内容,可以翻看我们之前的所有权v0R28资讯网——每日最新资讯28at.com

12. 结构体

struct,或者 structure,是一个「自定义数据类型」,允许我们命名和包装多个相关的值,从而形成一个有意义的组合。v0R28资讯网——每日最新资讯28at.com

图片图片v0R28资讯网——每日最新资讯28at.com

struct User {    active: bool,    username: String,    email: String,    sign_in_count: u64,}fn main() {    let mut user1 = User {        active: true,        username: String::from("front789"),        email: String::from("front789@example.com"),        sign_in_count: 1,    };    user1.email = String::from("anotheremail@example.com");    let user2 = User {        email: String::from("another@example.com"),        ..user1    };}

在 user2 中,你会看到 ..,它是扩展运算符,将 user1 中剩余的值传递给 user2(除了已经定义的 email)。v0R28资讯网——每日最新资讯28at.com

结构体的方法

使用 impl 结构体名,并在其中定义函数。v0R28资讯网——每日最新资讯28at.com

#[derive(Debug)]struct Rectangle {    width: u32,    height: u32,}impl Rectangle {    fn area(&self) -> u32 {        self.width * self.height    }}fn main() {    let rect1 = Rectangle {        width: 30,        height: 50,    };    println!(        "长方形的面积为 {}",        rect1.area()    );}

图片图片v0R28资讯网——每日最新资讯28at.com

针对此处更详细的内容,可以翻看我们之前的结构体v0R28资讯网——每日最新资讯28at.com

13. 枚举

枚举,也被称作 enums。枚举允许你通过「列举可能的成员variants来定义一个类型」v0R28资讯网——每日最新资讯28at.com

enum IpAddrKind {    V4,    V6,}let four = IpAddrKind::V4;let six = IpAddrKind::V6;

枚举的成员位于其标识符的「命名空间中」,并「使用两个冒号分开」。v0R28资讯网——每日最新资讯28at.com

match

这是类似于 switch 的东西,v0R28资讯网——每日最新资讯28at.com

enum Coin {    Penny,    Nickel,    Dime,    Quarter,}fn value_in_cents(coin: Coin) -> u8 {    match coin {        Coin::Penny => 1,        Coin::Nickel => 5,        Coin::Dime => 10,        Coin::Quarter => 25,    }    let number = 5;    match number {        1 => println!("One"),        2 => println!("Two"),        3 | 4 | 5 => println!("Three, Four, or Five"),        _ => println!("Other"), // 默认情况    }}

每个分支相关联的代码是一个表达式,而表达式的结果值将作为整个 match 表达式的返回值。v0R28资讯网——每日最新资讯28at.com

Option 枚举和其相对于空值的优势

图片图片v0R28资讯网——每日最新资讯28at.com

if Let

这是一种使用 if 的花式方式,我们在其中定义一个表达式。v0R28资讯网——每日最新资讯28at.com

fn main() {    let optional_number: Option<i32> = Some(5);    // 使用 if let 匹配 Some 变体并提取内部值    if let Some(num) = optional_number {        println!("Value: {}", num);    } else {        println!("No value");    }}

14. 并发性

并发编程和并行编程

图片图片v0R28资讯网——每日最新资讯28at.com

代码实现

为了创建一个新线程,需要调用 thread::spawn 函数并「传递一个闭包」,并在其中包含希望在新线程运行的代码。v0R28资讯网——每日最新资讯28at.com

可以通过将 thread::spawn 的「返回值储存在变量中来修复新建线程部分没有执行或者完全没有执行的问题」。thread::spawn 的返回值类型是 JoinHandle。JoinHandle 是一个「拥有所有权的值」,当「对其调用 join 方法时,它会等待其线程结束」。v0R28资讯网——每日最新资讯28at.com

use std::thread;fn main() {    // 数据    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];    // 将数据分成两部分    let mid = numbers.len() / 2;    let (left, right) = numbers.split_at(mid);    // 生成两个线程来计算每一半的总和    let handle1 = thread::spawn(move || sum(left));    let handle2 = thread::spawn(move || sum(right));    // 等待线程完成并获取它们的结果    let result1 = handle1.join().unwrap();    let result2 = handle2.join().unwrap();    // 计算最终总和    let total_sum = result1 + result2;    println!("Total sum: {}", total_sum);}fn sum(numbers: &[i32]) -> i32 {    let mut sum = 0;    for &num in numbers {        sum += num;    }    sum}

thread::spawn 要求闭包具有 'static 生命周期,这意味着它不会从周围范围借用任何东西,并且可以在整个程序的持续时间内存在。v0R28资讯网——每日最新资讯28at.com

因此,我们使用move 闭包,其经常与 thread::spawn 一起使用,因为它允许我们「在一个线程中使用另一个线程的数据」。v0R28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-85705-0.html一网打尽 Rust 语法

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 聊聊业务高可用的保障:异地多活架构

下一篇: 这个被忽略的细节,是编写优秀 Python 代码的必经之路

标签:
  • 热门焦点
  • 7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月份的手机市场风平浪静,除了红魔和努比亚带来了两款搭载骁龙8Gen2领先版处理器的新机之外,别的也想不到有什么新品了,这也正常,通常6月7月都是手机厂商修整的时间,进入8月份之
  • Raft算法:保障分布式系统共识的稳健之道

    Raft算法:保障分布式系统共识的稳健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可复制、可冗余、可容错”)的首字母缩写。Raft算法是一种用于在分布式系统
  • 掘力计划第 20 期:Flutter 混合开发的混乱之治

    掘力计划第 20 期:Flutter 混合开发的混乱之治

    在掘力计划系列活动第20场,《Flutter 开发实战详解》作者,掘金优秀作者,Github GSY 系列目负责人恋猫的小郭分享了Flutter 混合开发的混乱之治。Flutter 基于自研的 Skia 引擎
  • 把LangChain跑起来的三个方法

    把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    来源:极点商业作者:杨铭在淘宝购买珠宝玉石后,因为保证金不够赔付,店铺关闭,退货退款难、维权无门的比比皆是。&ldquo;提供相关产品鉴定证书,支持全国复检,可以30天无理由退换货。&
  • 大厂卷向扁平化

    大厂卷向扁平化

    来源:新熵作者丨南枝 编辑丨月见大厂职级不香了。俗话说,兵无常势,水无常形,互联网企业调整职级体系并不稀奇。7月13日,淘宝天猫集团启动了近年来最大的人力制度改革,目前已形成一
  • 东方甄选单飞:有些鸟注定是关不住的

    东方甄选单飞:有些鸟注定是关不住的

    作者:彭宽鸿来源:华尔街科技眼&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一
  • 三星Galaxy Z Fold5今日亮相:厚度缩减但仍略显厚重

    三星Galaxy Z Fold5今日亮相:厚度缩减但仍略显厚重

    据官方此前宣布,三星将于7月26日也就是今天在韩国首尔举办Unpacked活动,届时将带来带来包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy
  • 2299元起!iQOO Pad开启预售:性能最强天玑平板

    2299元起!iQOO Pad开启预售:性能最强天玑平板

    5月23日,iQOO如期举行了新品发布会,除了首发安卓最强旗舰处理器的iQOO Neo8系列新机外,还在发布会上推出了旗下首款平板电脑——iQOO Pad,其搭载了天玑
Top