熟悉 Rust 的语法

2025-06-05

熟悉 Rust 的语法

所以,您决定学习 Rust。

不错的选择!Rust 是一门很棒的语言,它结合了系统编程的强大功能和现代语言特性,可以用于 Web 开发和区块链。

然而,在学习 Rust 时,其中一个障碍就是熟悉它的语法。

在本文中,我将尽力提供一些让您感到舒服的示例。

入门:变量和类型

让我们从基础开始:变量。

默认情况下,Rust 变量是不可变的。如果你习惯使用 Python 或 JavaScript 等允许变量更改的语言,这可能听起来很奇怪。

fn main() {
    let x = 5; // x is immutable by default
    // x = 6; // Uncommenting this will throw a compiler error

    let mut y = 5; // y is mutable
    y = 6; // No problem here
}
Enter fullscreen mode Exit fullscreen mode

注意到let关键字了吗?这就是 Rust 中声明变量的方式。如果要更改变量,请使用 mut 关键字使其可变。

类型注解

Rust 具有很好的类型推断:编译器通常知道变量的类型。

但有时,您需要自己指定类型:

// Here, we're explicitly saying that z is a 32-bit integer
let z: i32 = 10; 
Enter fullscreen mode Exit fullscreen mode

Rust 的类型系统是其一大优势,因此值得尽早熟悉它。

功能

如果你使用过其他语言,Rust 中的函数看起来应该很熟悉。但是有一些语法怪癖需要注意。

fn add(a: i32, b: i32) -> i32 {
    a + b // No semicolon means this is the return value
}
Enter fullscreen mode Exit fullscreen mode

注意,我们使用 -> 来定义函数的返回类型。另外,这里没有 return 关键字;如果省略分号,Rust 默认返回最后一个表达式。

一旦习惯了就会感觉很好。

所有权和借款

好吧,事情开始变得有趣了。Rust 的所有权模型让它脱颖而出,但一开始可能会有点棘手。

让我们看另一个例子

所有权

在 Rust 中,每个值都有一个变量,它是它的所有者。

当所有者超出范围时,该值将被丢弃。这就是 Rust 避免内存泄漏的方法。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // Ownership of the String is moved to s2, s1 is now invalid

    // println!("{}", s1); // This would cause a compile-time error
}
Enter fullscreen mode Exit fullscreen mode

这里,当字符串移动到 s2 之后,s1 不再拥有该字符串。

如果你之后尝试使用 s1,Rust 将不会让你这么做。这就像 Rust 在说:“嘿,这已经不是你的了。”

借款

但是如果你想使用一个值而不拥有它的所有权该怎么办呢?

这就是借用的地方。您可以通过使用引用来借用一个值:

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1); // We're borrowing s1 here

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}
Enter fullscreen mode Exit fullscreen mode

在这个例子中,&s1 是references1 的 a 。calculate_length 函数暂时借用了 s1 ,但没有取得所有权。函数执行完毕后,s1 仍然有效。这很酷。

生命周期

生命周期是 Rust 跟踪引用有效时间的方式。

它们最初可能会令人困惑,但它们对于安全的内存管理至关重要。

让我们看一个非常基本的例子来熟悉它。

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
Enter fullscreen mode Exit fullscreen mode

这里, 'a 是一个生命周期参数。这意味着引用 x 和 y 必须至少与返回值一样长。这确保我们不会返回对已经被丢弃的对象(或对象)的引用。

模式匹配

Rust 的 match 语句就像是兴奋剂一样。它是我最喜欢 Rust 的部分之一,因为它功能强大,表达力极强。

fn main() {
    let number = 7;

    match number {
        1 => println!("One!"),
        2 => println!("Two!"),
        3 | 4 | 5 => println!("Three, Four, or Five!"),
        6..=10 => println!("Between Six and Ten!"),
        _ => println!("Anything else!"),
    }
}
Enter fullscreen mode Exit fullscreen mode

match 语句会根据多个模式检查一个值,并运行第一个匹配模式的代码。_ 是一个包罗万象的模式,当你需要处理任何未明确匹配的内容时非常有用。

使用模式匹配进行解构

您还可以使用它match来解构元组或枚举等复杂数据类型。

fn main() {
    let pair = (2, 5);

    match pair {
        (0, y) => println!("First is zero and y is {}", y),
        (x, 0) => println!("x is {} and second is zero", x),
        _ => println!("No zeroes here!"),
    }
}
Enter fullscreen mode Exit fullscreen mode

这只是皮毛而已。

Match 可以做更多的事情,但这应该能为你打下坚实的基础。

错误处理

Rust 没有异常。相反,它使用 Result 和 Option 类型来处理错误。乍一看可能有点冗长,但它比未检查异常安全得多。

fn main() {
    let result = divide(10, 2);
    match result {
        Ok(v) => println!("Result is {}", v),
        Err(e) => println!("Error: {}", e),
    }
}

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("Division by zero"))
    } else {
        Ok(a / b)
    }
}
Enter fullscreen mode Exit fullscreen mode

这里的Result类型可以是 Ok(成功)或 Err(错误)。这迫使你处理成功和失败的情况,这对于编写健壮的代码非常有用。

?操作

为了使错误处理更加人性化,Rust 提供了?Operator。它是传播错误的简写。

fn main() -> Result<(), String> {
    let result = divide(10, 0)?; // If divide returns Err, it returns from the function immediately
    println!("Result is {}", result);
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

这就是 Rust 的说法,“如果出现错误,就返回它。”

高级语法:特征、泛型等

现在我们已经掌握了基础知识,让我们深入研究更高级的主题。

特征:接口(有点)

特质有点像其他语言中的接口。它们定义了不同类型可以实现的共享行为。

trait Summary {
    fn summarize(&self) -> String;
}

struct Article {
    title: String,
    content: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.content)
    }
}
Enter fullscreen mode Exit fullscreen mode

这里,我们为 Article 结构体定义并实现了一个 Summary trait。现在,任何文章都可以被概括了。Trait 对于编写通用且可复用的代码非常有效。

泛型:编写灵活的代码

泛型允许您编写适用于任何数据类型的函数和类型。

fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}
Enter fullscreen mode Exit fullscreen mode

此函数适用于任何可比较的类型 T。PartialOrd 部分是 trait 绑定的,这意味着 T 必须实现 PartialOrd trait,才能进行排序比较。

实用技巧:编写符合 Rust 语言习惯的程序

  • 使用 rustfmt:Rust 内置了格式化程序,可以让你的代码看起来更简洁。只需在项目目录中运行 cargo fmt 即可。

  • 使用 Rust Analyzer:这款强大的 IDE 扩展提供代码补全、重构等功能。它就像一位对 Rust 了如指掌的助手。

  • Clippy:这是一款 Rust 的 linter,可以捕获常见错误并提出改进建议。运行 cargo clippy 即可查看它发现了什么。

结论

这篇简短的文章是为了让您更熟悉 Rust。

我有一系列关于这些特定主题的免费视频。

您可以在这里查看

文章来源:https://dev.to/francescoxx/getting-familiar-with-rusts-syntax-35cd
PREV
Rust 🦀 使用 Docker 的 CRUD Rest API 🐳
NEXT
C#(C Sharp)使用 .NET 7、ASP.NET、Entity Framework、Postgres、Docker 和 Docker Compose 的 CRUD Rest API