本文详尽地介绍了 Rust 的所有权、借用及其相关概念,包括 Rust 的复制类型、可变性、泛型、Option 和 Result 等内容。通过示例代码,深入解释了 Rust 的独特语法和其内在逻辑,尤其适合有 Solidity 或 JavaScript 背景的开发者。此外,文章结构清晰,包含代码示例和必要的注释,帮助读者更好地理解 Rust 编程语言。
来自Solidity或JavaScript背景的读者可能会发现Rust中&
、mut
、<_>
、unwrap()
和?
的用法和语法显得奇怪(甚至丑陋)。本章将解释这些术语的含义。
如果一开始没有完全理解,不用担心。如果你忘记了语法定义,随时可以回来再读这个教程。
&
解引用运算符 *
):要理解&
和*
,我们首先需要了解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()的实现未显示
// 这段代码无法编译
在第一段代码中,a
和b
相加,只需要从变量复制64位数据(32位 * 2变量)。
然而,在字符串的情况下,我们并不总是知道要复制多少数据。如果字符串长达1GB,程序会显著变慢。
Rust希望我们明确如何处理大型数据。它不会像动态语言那样在后台自动复制。
因此,当我们做一些简单如_将字符串赋值给新变量_的操作时,Rust会做一些许多人认为意外的事情,正如我们在下一节所见。
对于非复制类型(字符串、向量、结构体等),一旦值被赋给变量,该变量便“拥有”它。所有权的影响将在随后展示。
以下代码无法编译。解释在注释中:
// 非复制数据类型(字符串)上更改所有权的示例
let s1 = String::from("abc");
// s2成为`String::from("abc")`的所有者
let s2 = s1;
// 以下行编译失败,因为s1无法再访问其字符串值。
println!("{}", s1);
// 这一行编译成功,因为s2现在拥有字符串值。
println!("{}", s2);
要修复上面的代码,我们有两个选择:使用&
运算符或克隆s1
。
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中的字符串值的引用。
}
如果我们希望另一个变量“查看”值(即获得只读访问权限),我们使用&
运算符。
要给另一个变量或函数查看一个拥有的变量,我们在前面加上&
。
可以将&
视为非复制类型的“仅视图”模式。我们所称的“仅视图”的技术术语是借用。
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...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!