从一个 PHP 开发者的角度来看 Rust

我第一次开始学习 Rust 大约在 6 个月前,当时我正在寻找一门新的语言学习时,我遇到了它。刚开始的时候我以为 Rust 是一门底层系统编程语言,但随着我学习的深入,我越发意识到它具有成为一门高级编程语言和编写 Web 应用的潜力。 此外,在学习的过程中,我还学习了许多 Rust 可以避免像许多其他编程语言编写的应用程序中经常出现的典型的 bug 的方法。

让我们来研究一下用 Rust 编写 web 应用程序所带来的一些好处。

强类型

在 Rust 中,所有内容都是强类型的,并在编译时进行检查。例如,如果程序中的函数接受 String 类型的参数,并且程序编译成功,则可以保证函数所接受的值只有字符串。因此,您可以避免编写在运行时检查参数的类型是否正确的防御性代码,或者参数是否为 null 的防御性代码。这使程序运行得更快,消除了与类型相关的错误的可能性,并使您编写的代码更少。

pub fn generate_greeting(name: String) -> String
{
  format!("Hi {}!", name)
}

pub fn main()
{
  let greeting = generate_greeting(String::from("Diego"));
  println!("{}", greeting);    
}

甚至更进一步,它还强制了表达式中使用的值的类型,例如 if 语句。在其他语言中,通常可以使用非布尔类型(如整数或字符串)作为 if 语句的条件,
当在这种情况下,这通常会导致 Rust 出现意外的行为。在 Rust 中你必须始终提供一个boolean 类型,这样可以确保结果是程序员的意图,Rust不会根据某些内部因素或程序员可能熟悉或不熟悉的规则来猜测某些内容是假的还是真的,以下代码将不会在Rust中编译:

pub fn main()
{
    let number = 0;

    if number {
        println!("number is not falsy!");
    }
}

编译器将显示以下相当有用的错误信息:

6 |     if number {
  |        ^^^^^^ expected bool, found integral variable

默认不可变

在我看来,在 Rust 中编写的另一个好处是,默认情况下,一切都是不可变的。这可以限制您在明确的情况下使某些需要改变的内容被允许改动,从而防止出现某些数据在您不打算改变时发生改变的意外情况。

看下面这个例子:

pub fn walk_dogs(dogs: &Vec<&str>)
{
    for dog in dogs {
        println!("Walking a {}...", dog);
    }
}

pub fn main()
{
    let dogs_collection = vec!["German Spitz", "Golden Retriever", "Akita"];
    walk_dogs(&dogs_collection);

    //这一直会是 true,因为 dogs_collection 变量是可变的。
    assert_eq!(dogs_collection, vec!["German Spitz", "Golden Retriever", "Akita"]);
}

事实上,我们可以将我们的狗的集合传递给一个方法,并保证数据根本没有改变,对于我来说这是令人兴奋的事情,并成为 Rust 的一个令人上瘾的功能。很明显,在上面的例子中 walk_dogs 方法不会改变我们的集合,但是如果它是来自另一个库的方法呢?那么我们是否需要确保数据被函数调用后没有发生改变?即使该方法现在没有改变它的值,但是我们无法知道在未来版本的库中会不会被实现。

另一方面,我们可以放心地使用 Rust,它的方法不会改变数据,因为我们正在将一个不可变的引用传递给 dogs_collection 向量。如果 walk_dogs 方法试图以任何方式改变此数据,此代码将无法编译,因为它会破坏 Rust 的所有权规则。所有权规则是使 Rust 语言变得独特的特性之一,你可以在 Rust 手册中阅读与这些特性相关的更多信息。

但是,如果我们想让函数来改变数据,那么函数签名和调用函数的代码都必须通过显式地传递和接受可变引用,来明确改变数据的意图。如下例所示:

pub struct Product
{
    name: String,
    price: f32,
    stock: i32
}

pub fn purchase_product(product: &mut Product, qty: i32)
{
    // 省略采购逻辑
    product.stock = product.stock - qty;
}

pub fn main()
{
    let mut product = Product { name: String::from("Green Armchair"), price: 150.50, stock: 30};
    purchase_product(&mut product, 5);

    assert_eq!(product.stock, 25);
}

在这里你可以看到我们通过使用 mut 关键字就可以立即定义变量 product 为可变的,这告诉 Rust 我们打算改变这个变量,这引入了一些限制,例如我们一次只能对一个值进行可变引用,从而保护您的代码免受数据竞争冲突。 注意,purchase_product 函数签名还必须使用 &mut Product 语法明确指定它接受对Product 的可变引用,编译器会确认这种情况。最后我们可以看到 product.stock 属性在函数内部发生了改变,订购的数量已被减去,产品 product 对象的库存 stock 现在为 25。

枚举和模式匹配

枚举和代数数据类型在 Rust 中广范使用。用下面的例子来说明枚举和完备的模式匹配的威力。我最喜爱的 Rust 设计之一就是它没有 null 类型。Rust 中没有变量可以为空类型。那如何表示值缺失呢?你猜到了,就是枚举!

pub enum Option<T> {
    None,
    Some(T),
}

事实上,Rust 中用 Option 表示数据的缺失和存在,注意到 Option 还是一个泛型。表示没有值时 Option 为 None, 表示有值时为 Some

看看下面的例子是如何使用 Option 枚举的:

pub struct Customer {
    id: i32,
    name: String
}

pub fn get_customer_by_id(id: i32) -> Option<Customer>
{
    //从数据库获取客户信息
}

pub fn main()
{
    let customer = get_customer_by_id(32);
}

这里我们有一个 Customer 结构,把它想象成其他语言的类,比如 PHP 和从 DB 加载客户 customer 的函数。具有给定 id 的客户 customer 不存在于 DB 中的可能。因此,我们需要返回选项以允许不存在客户的可能性。现在,我们不能只假设 get_customer_by_id 返回的客户 customer 是 Customer 的一个实例,如果我们尝试这样做,我们的程序就不会编译,编译器不仅不允许你假设你有一个 Customer 的实例,它还会强制你完整处理函数返回的及枚举的每个可能的变量,从而使您的代码健壮。

pub struct Customer {
    id: i32,
    name: String
}

pub fn get_customer_by_id(id: i32) -> Option<Customer>
{
    Some(Customer {id: 32, name: "Diego".to_string()})
}

pub fn main()
{
    let customer = get_customer_by_id(32);

    match customer {
        Some(a) => println!("Customer name: {}", a.name),
        None => println!("Customer not found")
    }
}

使用匹配运算符,我们能够处理调用 get_customer_by_id 函数的每个可能的结果。请注意,我们可以从枚举中提取数据,在这个例子中,Customer 实例最终匹配在匹配表达式的第一个臂柄的变量 a 中,然后我们可以在 => 的右侧使用它。

大多数编程语言都不会强制检查变量的值,大量的代码漏洞是由于假设函数返回某种类型的值,但有时却会返回另一种类型。如果你不检查所有可能的类型 Rust 类型系统会有你的后门,而编译器将不允许你编译你的代码。

更多

这里我只是接触一点表皮,Rust 还有很多特征帮助你编译更快更安全的应用。如果:

  • 开箱即用的依赖管理
  • 相当好的模块系统
  • 没有继承
  • 特征
  • 无畏的并发
  • 等等

如果你喜欢这篇介绍,而且想开始学习 Rust , 你可以查看官方的 Rust Book. 你也可以看看 Web 相关的库和框架在 Are we web yet?

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://www.smashing-bugs.tk/software-de...

译文地址:https://learnku.com/rust/t/29041

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 5

这个语言好像很厉害的样子!

4年前 评论
chongyi

配合各种编译时的检查,最重要的还有极其强悍的性能

4年前 评论
Summer

@chongyi 期待你的 Rust 实战分享哈

4年前 评论
阿麦

时隔大半年回来看 RUST 越来越好了 微软采用了它开发了部分业务 DENO 也用到了

3年前 评论
zhanghaidi

rust感觉挺好,就是有点难,很多概念,第一次解除,不过值得学习

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!