Rust不寻常的语法

  • RareSkills
  • 发布于 2024-10-10 19:54
  • 阅读 277

本文详尽地介绍了 Rust 的所有权、借用及其相关概念,包括 Rust 的复制类型、可变性、泛型、Option 和 Result 等内容。通过示例代码,深入解释了 Rust 的独特语法和其内在逻辑,尤其适合有 Solidity 或 JavaScript 背景的开发者。此外,文章结构清晰,包含代码示例和必要的注释,帮助读者更好地理解 Rust 编程语言。

Rust的奇特语法

来自Solidity或JavaScript背景的读者可能会发现Rust中&mut<_>unwrap()?的用法和语法显得奇怪(甚至丑陋)。本章将解释这些术语的含义。

如果一开始没有完全理解,不用担心。如果你忘记了语法定义,随时可以回来再读这个教程。

所有权与借用(引用 & 解引用运算符 *):

Rust的复制类型

要理解&*,我们首先需要了解Rust中的“复制类型”。复制类型是一种数据类型,其值的复制开销微不足道。以下值是复制类型:

  • 整数、无符号整数和浮点数
  • 布尔值
  • 字符

它们被称为“复制类型”,是因为它们的大小固定且较小。

另一方面,向量、字符串和结构体可以任意大,因此它们不是复制类型。

为什么Rust区分复制类型和非复制类型

考虑以下Rust代码:

pub fn main() {
    let a: u32 = 2;
    let b: u32 = 3;
    println!("{}", add(a, b)); // a和b被复制到add函数

    let s1 = String::from("hello");
    let s2 = String::from(" world");

    // 如果s1和s2被复制,可能会发生巨大的数据传输
    // 如果字符串非常长
    println!("{}", concat(s1, s2));
}

// 为了简洁,add()和concat()的实现未显示
// 这段代码无法编译

在第一段代码中,ab相加,只需要从变量复制64位数据(32位 * 2变量)。

然而,在字符串的情况下,我们并不总是知道要复制多少数据。如果字符串长达1GB,程序会显著变慢。

Rust希望我们明确如何处理大型数据。它不会像动态语言那样在后台自动复制。

因此,当我们做一些简单如_将字符串赋值给新变量_的操作时,Rust会做一些许多人认为意外的事情,正如我们在下一节所见。

Rust中的所有权

对于非复制类型(字符串、向量、结构体等),一旦值被赋给变量,该变量便“拥有”它。所有权的影响将在随后展示。

以下代码无法编译。解释在注释中:

// 非复制数据类型(字符串)上更改所有权的示例
let s1 = String::from("abc");

// s2成为`String::from("abc")`的所有者
let s2 = s1;

// 以下行编译失败,因为s1无法再访问其字符串值。
println!("{}", s1);

// 这一行编译成功,因为s2现在拥有字符串值。
println!("{}", s2);

要修复上面的代码,我们有两个选择:使用&运算符或克隆s1

选项 1:给s2一个s1的视图

在下面的代码中,注意重要的&前缀s1

pub fn main() {
    let s1 = String::from("abc");

    let s2 = &s1; // s2现在可以查看`String::from("abc")`但不能拥有它

    println!("{}", s1); // 这段代码编译,s1仍然保持其原始字符串值。
    println!("{}", s2); // 这段代码编译,s2持有对s1中的字符串值的引用。
}

如果我们希望另一个变量“查看”值(即获得只读访问权限),我们使用&运算符。

要给另一个变量或函数查看一个拥有的变量,我们在前面加上&

可以将&视为非复制类型的“仅视图”模式。我们所称的“仅视图”的技术术语是借用

选项 2:克隆s1

要理解我们如何可以克隆一个值,考虑以下示例:

fn main() {
    let mut message = String::from("hello");
    println!("{}", message);
    message = message + " world";
    println!("{}", message);
}

上面的代码将打印“hello”,然后打印“hello world”。

但是,如果我们添加一个查看message的变量y,代码将无法再编译:

// 无法编译
fn main() {
    let mut message = String::from("hello");
    println!("{}", message);
    let mut y = &message; // y正在查看message
    message = message + " world";
    println!("{}", message);
    println!("{}", y); // y应该是"hello"还是"hello world"?
}

Rust不接受上面的代码,因为变量message在被查看时不能重新赋值。

如果我们希望y能够在不干扰message的前提下复制message的值,我们可以选择克隆它:


fn main() {
    let mut mes...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/