Rust学习笔记(一)|Rust初体验 猜数游戏

本篇文章包含的内容

  • [1 从`main`函数开始](#1 从main函数开始)
  • [2 `Cargo.toml`](#2 Cargo.toml)
  • [3 变量和标准输入输出](#3 变量和标准输入输出)
  • [4 在Rust中使用包crate](#4 在Rust中使用包crate)
  • [5 类型转换与match语句](#5 类型转换与match语句)

1 从main函数开始

Rust的程序和C/C++类似,也从main函数开始。定义一个main函数,并使用宏(macro)打印hello world:

rust 复制代码
fn main() {
	println!("hello world");
}

Rust的编译器是rustc,假设上面的文件名为main.rs,则可以使用下面的命令编译生成可执行文件:

bash 复制代码
rustc main.rs

实际开发中,rustc只适用于简单的Rust程序,一般不直接使用rustc,而是使用Rust自带的工程管理工具Cargo来编译和管理工程。Cargo是Rust的系统构建工具和包管理工具 。可以使用下面的命令创建一个工程,这将生成一个名为hello_cargo的文件夹。博主一般使用RustRover开发Rust程序,所以这部分工作不需要开发者关心,了解即可。

bash 复制代码
cargo new hello_cargo

生成的项目结构如下所示:

  • hello_cargo
    • src
    • Cargo.toml
    • .gitignore

2 Cargo.toml


Cargo.toml文件是Rust项目的配置文件,默认包含包信息[package]和依赖库信息[dependencies]两部分。在Rust中,依赖库(代码包)被称为crate。

在项目根目录下执行下面的命令来编译Cargo工程或者运行可执行文件,并生成用于追踪工程依赖库版本的Cargo.lock文件。

bash 复制代码
cargo build		# 编译到target目录下
cargo build --release	

cargo run		# 编译并运行

cargo check		# 检查语法,但不执行编译,速度快得多

3 变量和标准输入输出

Rust中使用let关键字声明变量,声明的变量默认是不可变的,如果要声明一个可变的变量,需要额外添加mut关键字。

rust 复制代码
let mut foo = 1;
let bar = 2;

foo = 3;	// 合法

let mut guess: String = String::new();

在上面的程序片段最后,声明了一个名为guess的可变变量,并使用String类的一个关联函数 (针对类本身的函数,而不针对具体实例)new创建了一个空白字符串实例。

下面的例子使用标准库std::io处理终端输入。stdin()方法返回一个Stdin实例,它有一个方法称为read_line(),这个方法需要一个可变的参数(参数会随着用户的更改而更改),同时使用&符号表示这里使用了引用作为函数的参数,在Rust中引用默认也是不可变的,所以这里需要mut关键字。如果读取失败,则会返回一个io::Result类型,它是一个枚举类型,有两个变体:Ok、Err。我们需要对Result的每一种情况都进行处理,这里使用expect方法进行处理,如果输入失败,它会中断程序,并打印其中的信息。

rust 复制代码
use std::io;	// 显式指定prelude

fn main() {
    println!("Guessing Game Start!");

    let mut guess:String = String::new();
    io::stdin().read_line(&mut guess).expect("input error!");

    println!("Your Guessing number is {}", guess);
}

4 在Rust中使用包crate

Rust中的包有两种,一种是可生成可执行文件的二进制库,还有一种是无法生成二进制文件的库包,crate属于后者。在Cargo.toml文件中声明需要的包及其语义版本,Cargo就会开始自动下载和构建包。

rust 复制代码
use std::io;
use rand::Rng;      // trait

fn main() {
    println!("Guessing Game Start!");

    let secret_number = rand::rng().random_range(1..101);
    println!("secret number is {}", secret_number);

    let mut guess:String= String::new();
    io::stdin().read_line(&mut guess).expect("input error!");

    println!("Your Guessing number is {}", guess);
}

5 类型转换与match语句

rust 复制代码
use std::io;
use rand::Rng;      // trait
use std::cmp::Ordering;

fn main() {
    println!("Guessing Game Start!");

    let secret_number = rand::rng().random_range(1..101);	// 自动类型推断secret_number为u32
    println!("secret number is {}", secret_number);

    let mut guess: String = String::new();
    io::stdin().read_line(&mut guess).expect("input error!");

    let guess : u32 = guess.trim().parse().expect("Please input a number!");	// shadow,变量名遮蔽

    match guess.cmp(&secret_number) {
        Ordering::Greater => println!("Too big!"),		// arm,分支
        Ordering::Less => println!("Too small!"),
        Ordering::Equal => println!("You win!")
    }

    println!("Your Guessing number is {}", guess);
}

在上面的程序中,我们尝试从控制台获取了一个输入。现在需要将其转化为整数类型并与随机数相比较。在Rust中,支持变量遮蔽,即声明的新的同名变量会完全替代掉后面的变量,之后的程序段都采用新的变量定义,这样的做法省去了重新为变量命名的苦恼 。在这里,我们声明了一个新的变量guess : u32,后续的程序段中guess都将指整数类型,而不是之前定义的可变字符串类型。

在为guess : u32变量赋初值时,仍然需要用到之前的guess : String变量。这里使用两个方法,trim()去除字符串左右两边的空白符号,包括空格和换行符;parse()将字符串类型转换为整数类型,具体转换成哪种整数类型,Rust可以根据上下文进行自动类型推断。之后,对返回的Reuslt实例进行处理,包括对非法输入情况。

可以看到,Rust和C/C++相比显现出的一个很大的不同是Rust使用千方百计来使得程序获得更高的鲁棒性,防御性变成的思想被融入到整个编程语言中。

match语句是Rust中的常用语句,其将match后的表达式的返回值与其分支(arm)进行匹配,匹配成功则执行后续的代码。上面的程序中,首先导入了标准库中的Ordering枚举,该枚举有三个变体:LessGreaterEqual。匹配成功则执行后续的代码。注意这里的match语句后没有添加分号,各个分支之间使用逗号隔开。

下面使用loop语句使得这个程序更加完整,并处理一些意外情况。

rust 复制代码
use rand::Rng; // trait
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Guessing Game Start!");

    let secret_number = rand::rng().random_range(1..101);
    // println!("secret number is {}", secret_number);
    loop {
        println!("Please input a number!");
        let mut guess: String = String::new();
        io::stdin().read_line(&mut guess).expect("input error!");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,		// 如果是Ok则返回Ok携带的num
            Err(_) => continue,
        };

        match guess.cmp(&secret_number) {
            Ordering::Greater => println!("Too big!"),
            Ordering::Less => println!("Too small!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }

        // println!("Your Guessing number is {}", guess);
    }
}

在类型转换时,使用expect处理意外情况会使得程序直接崩溃,但是如果我们不希望程序崩溃,而是希望程序继续进行,则可以使用match语句使得执行开发者定义的操作。


*  原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、FPGA方面的学习笔记。*


相关推荐
好奇龙猫22 分钟前
AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第五篇:代码修复]
人工智能·学习
MIXLLRED23 分钟前
YOLO学习——训练进阶和预测评价指标
深度学习·学习·yolo
摇滚侠24 分钟前
Spring Boot 3零基础教程,WEB 开发 内容协商 接口返回 YAML 格式的数据 笔记35
spring boot·笔记·后端
Chunyyyen1 小时前
【第十八周】自然语言处理的学习笔记03
笔记·学习·自然语言处理
聪明的笨猪猪1 小时前
Java JVM “类加载与虚拟机执行” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
心.c1 小时前
如何学习Lodash源码?
前端·javascript·学习
FserSuN1 小时前
构建基于大语言模型的智能数据可视化分析工具的学习总结
学习·信息可视化·语言模型
im_AMBER2 小时前
React 02
前端·笔记·学习·react.js·前端框架
怀揣小梦想2 小时前
跟着Carl学算法--哈希表
数据结构·c++·笔记·算法·哈希算法·散列表
Nebula_g2 小时前
Java哈希表入门详解(Hash)
java·开发语言·学习·算法·哈希算法·初学者