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方面的学习笔记。*


相关推荐
wdfk_prog3 分钟前
[Linux]学习笔记系列 -- [arm][lib]
linux·运维·arm开发·笔记·学习
艾莉丝努力练剑6 分钟前
深入详解C语言的循环结构:while循环、do-while循环、for循环,结合实例,讲透C语言的循环结构
c语言·开发语言·c++·学习
晨非辰1 小时前
#C语言——学习攻略:自定义类型路线--结构体--结构体类型,结构体变量的创建和初始化,结构体内存对齐,结构体传参,结构体实现位段
c语言·开发语言·经验分享·学习·其他·学习方法·visual studio
蒋星熠2 小时前
Rust 异步生态实战:Tokio 调度、Pin/Unpin 与零拷贝 I/O
人工智能·后端·python·深度学习·rust
勇往直前plus2 小时前
一文学习nacos和openFeign
java·学习·微服务·openfeign
冬夜戏雪3 小时前
java学习 leetcode 二分查找 图论
java·学习·leetcode
影子打怪3 小时前
three.js学习记录(鼠标控制)
学习
KFCgrandpahhh3 小时前
从0开始跟小甲鱼C语言视频使用linux一步步学习C语言(持续更新)8.13
linux·c语言·学习
CDA数据分析师干货分享3 小时前
【CDA 新一级】学习笔记第1篇:数据分析的时代背景
大数据·笔记·学习·数据分析·cda证书·cda数据分析师