Rust语言从入门到入土 2:如此奇特的语法


人麻了,Rust的语法有点奇特。。。。。本文参考官方教程:https://kaisery.github.io/trpl-zh-cn/title-page.html

直观的感受一下Rust程序

Rust语言从入门到入土 2:如此奇特的语法

上次介绍了Rust的基础工具,这次首先通过一个程序介绍Rust的基础输入输出等内容,然后再介绍Rust的语法。

1. Hello World

编程语言入门第一课,必须得是hello world程序。我们先来看看Rusthello world是什么样子

cargo new hello_world
code hello_world

然后在src/main.rs中编写如下的代码:

// main.rs
fn main() {
    let s = "Hello World!\n";
    println!("{s}");
}

然后编译、运行该项目

cargo run

运行结果

A. 分析程序

我们接下来分析一下这个程序

1) 文件名:main.rs

一般Rust源代码的后缀名使用.rs表示,Cargo项目中源码都放在src目录下。源码一定要注意使用utf8编码

2) 注释:// main.rs

第一行是注释语句,Rust的注释是C语言系列风格的,行注释采用//开头,块注释使用/**/包围。

此外,类似PythondocstringRust它还支持更高级的文档注释,即对文档、函数等等对象进行注释,后文中将详细展开说明。

3) 函数:fn

fn是一个关键字keyword),函数定义必须以这个关键字开头fn是单词function的缩写,在Rust中,设计者比较偏向使用单词缩写,即使是关键字也不例外。在代码风格上, 某些读者可能开始会有点不习惯。但总体而言,这只是个审美偏好而已,不必过于纠结,习惯就好。

函数体使用大括号来包含。

如果我们要定义的函数有参数和返回值,可以使用以下语法(参数列表使用逗号分开,冒号后面是类型,返回值类型使用->符号分隔)

fn Foo(input1 : i32, input2 : u32) -> i32 {
    ...
}

4) 主函数:main

默认情况下,main函数是可执行程序的入口点,它是一个无参数,无返回值的函数

5) 局部变量:let

局部变量声明使用let关键字开头,用双引号包含起来的部分是字符串常量。Rust是静态强类型语言,所有的变量都有严格的编译期语法检查。关于Rust的变量和类型系统将在后文详细说明。

6) 语句:let s = "Hello World!\n";

  • Rust中每条语句使用分号结尾。
  • 语句块使用大括号。
  • 空格、换行和缩进不是语法规则的一部分。

这都是明显的C语言系列的风格。

7) 标准输出:println!

Rust最简单的标准输出是使用println!宏来完成。请大家一定注意println!后面的感叹号,它代表这是一个宏,而不是一个函数。

Rust中的宏与C/C++中的宏是完全不一样的东西。简单点说,可以把它理解为一种安全版的编译期语法扩展。这里之所以使用宏,而不是函数,是因为
标准输出宏可以完成编译期格式检查,更加安全。

从这个小程序的惊鸿一瞥中,大家可以看到,Rust的语法主要还是C系列的语法风格。对于熟悉C/C++/Java/C#/PHP/JavaScript等语言的读者来说,会看到许多熟悉的身影。

B. createmod

2. 猜数游戏

本章将介绍Rust中一些常用概念,并通过真实的程序来展示如何运用它们。具体包括:

  • let
  • match
  • 方法method
  • 关联函数associated function
  • 外部crate

这里是简单的介绍,后续章节会深入探讨这些概念的细节

A. 程序功能

猜数游戏是这么工作的:

  • 程序将会随机生成一个 1 到 100 之间的随机整数
  • 接着程序会请玩家猜一个数并输入
  • 程序接着会:
    • 如果玩家猜对了,它会打印祝贺信息并退出
    • 如果玩家猜错了,他会提示猜测是大了还是小了

B. 创建项目

前面我们说到,尽量使用Cargo来管理Rust项目。所以这里我们直接使用Cargo来创建项目

cargo new guessing_game
cd guessing_game
code ./

然后就会打开VSCode

接着编译、运行一下项目(我这里就在VSCode的终端了)

cargo run

运行结果

C. 编写代码

我们接下来就开始在src/main.rs中编写代码了。

1) 获取用户输入

学习任何一门语言,最开始的一定都是学习这门语言的输入输出。前面的例子里我们已经看到,Rust打印字符串的函数是println!,这里我们介绍Rust如何获取用户的输入

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {guess}");
}
a) use std::io

类似于C接受用户输入需要#include <sdtio.h>C++接受用户输入需要#incldue <iostream>Rust接受用户输入首先需要use std::io

Rust的代码从逻辑上是分cratemod管理的

  • 所谓crate大家可以理解为项目,或者。每个crate是一个完整的编译单元,它可以生成为一个lib或者exe可执行文件。而在crate内部,则是由mod这个概念管理的
  • 所谓mod大家可以理解为namespace。我们可以使用use语句把其他模块中的内容引入到当前模块中来

这里:

  • iomod的名字,io这个mod中提供了输入/输出函数。io 这个modstd这个create(库)的一部分,因此在前面加上 std::
  • use等价于C/C++中的#includePython中的import。注意,默认情况下,Rust会自动把标准库的一些内容自动导入到当前程序,这些内容被称为预导入Preclude) 内容。我们需要使用的类型、函数不在预导入内容中,就必须使用 use 语句显式地将其导入

io库的内容

b) println!

我们前面介绍了,println!可以用于向终端打印字符串。但实际上和C/C++printf是函数不同,Rust中的println!是一个宏

类似于C/C++有宏,Rust中也有宏。宏可以在编译时进行代码展开,因此可以避免在运行时进行函数调用的开销。这对于频繁调用的函数来说非常重要,因为它可以显著提高程序的性能。

println!就是一类非常常用的函数,因此Rustprintln!设置为宏是为了提高Rust程序的效率。

println!宏的定义

c) let

letRust的关键字,用于声明一个变量。例如下面我们声明了一个值为1的变量,变量名为a

let a = 1;

但是注意,Rust中默认所有的变量的值都是不可以改变的。如果我们尝试改变,在编译阶段就会报错。例如:

fn main() {
    let a = 1;
    a = 2;
}

编译会报错

最后的报错就是说我们尝试给一个变量a赋值两次。

除了报错以外这里还有两个警告,这里的两个警告主要是因为Rust是一个严格的语言:

  • 第一个警告是因为变量a从来没有被使用
  • 第二个警告是因为变量a中的值从来没有被使用过
d) mut

程序是无可避免的需要修改变量的值的。为此,Rust提供了一个关键字mut,使用该关键字,Rust允许我们修改被修饰的变量的值。

例如上面的程序,变量a使用mut关键字修饰后,再次编译就不会报错

fn main() {
    let mut a = 1;
    a = 2;
}

Rust之所以要这样设计,主要是避免了C/C++中使用const关键字的麻烦,因为要修饰指针不可变,或者指针指向的内容不可变。而且因为Rust是内存安全型的语言,相比让所有变量都是可变的而后声明不可变的变量,将所有变量都是不可变的而后声明可变的变量更安全

e) 打印变量

程序中我们无可避免的需要打印变量的值。在C/C++中通过格式化字符串或者重载来实现。

Rust实现打印变量的方式和Pythonformat-string类似,都是在打印的变量用{}包裹来输出变量。

fn main() {
    let a = 1;
    println!("num of a is {a}");
}

cargo run的结果

除了直接将变变量放在{}中之外,还可以把{}当做占位符,放在后面。

fn main() {
    let a = 1;
    println!("num of a is {}", a);
}

cargo run的结果

f) String::new()

RustC++类似,是一种多范式编程语言,支持面向对象编程、函数式编程和命令式编程等多种编程范式。


文章作者: Jack Wang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jack Wang !
  目录