📕
innohub
  • KEEP LEARNING
  • WebInfo
    • JS 部分运算符操作
    • javascript 中的object array
    • 错误处理以及异常捕获
    • JavaScript Bases
    • LaoZi & Confucius
  • PyInfo
    • Python3 输入与输出
    • Python3OS
    • python 修饰器的使用
    • python3 与mysql数据库连接使用实例
    • Format-specifier
    • CGI初学踩坑
    • Django 项目测试
    • Assert-info
    • 使用ngnix和uWSGI配置Django
    • write|SVN​
    • Matplotlib 基本使用
    • 重读 Python 官方文档
    • Python3 Base
    • python3 多线程
    • Python3 函数解析
    • python3 str 对象的基本操作
    • protocl buffers
    • Iterator-Generator
    • Django base
    • Decorator 2
    • Export to wheel or egg-info
    • 三. 运算、数据及逻辑
  • GoInfo
    • Info
      • Select 语句使用
      • First class function
      • Work Pools
      • StructTag
      • Go struct
      • 常用函数
      • Strings操作
      • Golang Bases
      • 数组以及切片
      • 文件操作
      • Golang 中的指针类型
      • Golang Map 类型
      • Reflection
      • 函数闭包
      • 接口
      • Panic and Recover
      • Go中的错误处理
      • 并发
      • defer usage
      • Method in golang
      • Object-oriented Programming
      • Goalng 包管理机制
  • RustInfo
    • Info
      • 包、crate、模块
      • Rust 中的错误处理
      • 智能指针
      • 泛型 generics
      • 数据布局与内存对齐
      • Functions and methods
      • 无畏并发
      • Actix-web 基本使用
      • Got from guessing game
      • 结构体的使用
      • Rust 中的函数式语言功能
      • 集合类型
      • 枚举以及模式匹配
      • Slice 类型
      • 生命周期
      • 测试
      • Rust 中的所有权
      • trait
      • 不安全 Rust
      • Format_print
      • Rust 通用编程概念
      • Macro
  • OS
    • info
      • 内存屏障 -- Part 1
      • 内存屏障 -- Part 2
      • CPU 上下文切换
      • 文件读写与零拷贝
      • ELF 文件
  • MySql
    • info
      • MySql 架构与历史
      • 02-key
  • kubernetes
    • 第二章 k8s 基本概念
    • 第一章 Kubernetes -- 伟大舵手
  • Redis
    • info
      • Redis 总览
      • 02-underline-ds
  • Shell&CInfo
    • GCC 与make的使用
    • C++ 中 malloc 与 new
    • 位运算符操作
    • Base of C macro
    • C 语言中 extern 关键字的用法
  • Distributed
    • info
      • 分布式理论概述
  • Java
    • info
      • Java 内存模型
  • Prometheus
    • Prometheus -- 不灭之火
Powered by GitBook
On this page
  • 1. 使用cargo构建项目
  • 1.1 构建以及运行
  • 2.2 发布版本
  • 2. 项目的配置文件
  • 3. 实现细节
  • 3.1 引入库
  • 3.2 程序入口
  • 3.3 使用变量
  • 3.4 引入包crate
  • 3.5 生成随机数
  • 3.6 数字比较
  • 3.7 使用循环
  • 3.8 通配符

Was this helpful?

  1. RustInfo
  2. Info

Got from guessing game

[TOC]

1. 使用cargo构建项目

Rustacean们使用cargo进行项目管理,使用cargo可以进行构建代码、下载依赖、编译依赖等任务。可以使用cargo new project_name命令来新建一个项目。新建该项目后,生成存放该项目的文件夹,并且生成了相应的项目配置文件Cargo.toml,首次运行cargo build时在项目的根目录下会生成一个Cargo.lock用以记录项目的真实依赖,该文件不需要手动操作,一切都有cargo自动完成。

1.1 构建以及运行

可以使用以下命令对于cargo项目进行构建以及运行测试:

cargo build
./target/debug/guessing_game

也可以使用一个命令完成编译以及测试的任务:

cargo run

cargo提供了一个快速检验代码的功能,不需要产生可执行文件,快速检查代码确保其可以通过编译。

cargo run
  • 使用cargo check检查项目

  • 使用cargo run进行一键测试

2.2 发布版本

当项目调试完毕,可以使用cargo build --release来优化编译项目,会在target/release目录下生成可执行文件,优化后的代码运行更快,但是需要更多的编译时间。所以设计两种不同的编译模式,一种适用于生产环境的测试,另一种适用于最终的产品发布。所以在测试代码的运行时间需要使用release版本,会有更快的运行速度。

2. 项目的配置文件

当新建一个项目时,在项目的根目录下会新建一个配置文件,里面包含了项目的基本信息,以及所使用的依赖和依赖的版本号。在目录src下进行代码的实现,进行快速迭代时可以使用cargo RUN进行快速的运行测试。src/main.rs是项目的入口源文件。

将所有的依赖写在Cargo.toml:

[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Inno Jia <jdgets111@gmail.com>"]
edition = "2018"

[dependencies]
rand  = "0.3.14"

3. 实现细节

3.1 引入库

使用关键字use引入需要使用的库文件,rust有一个标准库std。rust标准库是便携式rust软件的基础。这是一套针对广泛的rust生态系统设计的最小的经过实战考验的共享的抽象库。提供了核心的类型,语言基元的库定义操作,标准宏,I/O,多线程等。

以进行输入输出为例,需要引入use std::io

默认情形下Rust将prelude模块中的少量类型引入到每个程序的作用域,如果需要使用的类型不在prelude中,必须进行手动的引入。其中prelude是预引入的模块,因为标准库十分庞杂,对于一个作用域需要使用的类型如果全部手动引入会十分麻烦,但是引入过多没有用到的库会造成代码冗余。所以使用了预引入模块,预先引入尽可能少的库,包含每一个程序都可能使用到的内容。

3.2 程序入口

main.rs文件中的fn main(){}函数

3.3 使用变量

Rust中使用关键字let定义一个变量,由于Rust是静态类型的语言,对于每一个变量的声明都需要指明其类型,然后可以把一个初始化后的对象赋给变量,或者变量间的赋值,这与基本的静态类型语言一致。

let mut guess = String::new(); // String 是一个标准库提供的字符串类型,它是 UTF-8 编码的可增长文本块。
let foo = bar;

在Rust中变量默认是不可变类型,可以在变量声明时,在其前面加上mut关键字使之成为可变类型。

在Rust中使用一个类型的关联函数时需要借助::操作符,关联函数是针对于某个特定的类型实现的,而不是针对于某个对象,叫做静态方法,只可以使用类型加上::进行调用,这点与java相同;如果关联函数针对某一个特定的实例实现,可以通过实例.的方式进行调用。

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

使用io类型的stdin() 函数返回了一个标准输入的实例std::io::Stdin ,可以使用该实例进行终端的输入。然后调用该实例的read_line()方法,将用户输入存入到一个字符串中,该字符串以参数的形式传入其中,其参数类型是一个引用,可以对原字符串的内容进行更改,多处代码访问同一个数据而不需要在内存中多次赋值,与c语言一致,但是可变变量的使用需要加上mut关键字。

对于一个较长行可以在调用函数处换行,每一行使用;分隔。当调用ready_line(&)时返回一个io::Result 值。Result的类型是枚举,enums。枚举类型与c中的一致,包含了特定集合的值,Ok, Err, 分别代表操作是否成功。expect()方法如果接收到的是Err会使得程序终止,并且输出错误信息。

如果不使用expect(),程序编译时会发出警告,没有使用io::sidin()::read_line(&mut guess)的返回值。

3.4 引入包crate

在rust中包的概念使用crate表示,相当于其他语言中的package,library。一个crate中包含多个module。对于cargo项目如果需要引入一个包,可以在配置文件中的依赖性下进行添加。

rand crate是一个生成随机数的包,然后使用cargo build重新构建项目,此时carfo检查依赖发现本地没有,从registry上获取所有包的最新版本信息。然后检查【dependencies】片段并且下载缺失的crate,下载过程中会递归下载所有的依赖包。

Cargo 有一个机制来确保任何人在任何时候重新构建代码,都会产生相同的结果:Cargo 只会使用你指定的依赖版本,除非你又手动指定了别的。例如,如果下周 rand crate 的 0.3.15 版本出来了,它修复了一个重要的 bug,同时也含有一个会破坏代码运行的缺陷,这时会发生什么呢?

这个问题的答案是 Cargo.lock 文件。它在第一次运行 cargo build 时创建,并放在 guessing_game 目录。当第一次构建项目时,Cargo 计算出所有符合要求的依赖版本并写入 Cargo.lock 文件。当将来构建项目时,Cargo 会发现 Cargo.lock 已存在并使用其中指定的版本,而不是再次计算所有的版本。这使得你拥有了一个自动化的可重现的构建。换句话说,项目会持续使用 0.3.14 直到你显式升级。

更新crate

可以使用cargo update进行包更新,但是进行的是小版本更新,如果大版本更新,必须手动更改配置文件

3.5 生成随机数

引入随机数包后需要在项目中使用,use rand::Rng; Rng是一个trait可以认为是其他语言中的接口,定义了随机数生成器应实现的方法,这个trait必须在作用域中。Rng定义了gen_range方法,通过使用rand::thread_rng()静态方法实例化一个随机数生成器,然后该生成器实现了Rngtrait,所以可以调用该方法生成一个指定范围的随机整数。rand::thread_rng 函数提供实际使用的随机数生成器:它位于当前执行线程的本地环境中,并从操作系统获取 seed。

let num = rand::thread_rng().gen_range(1, 101)

对于一个trait定义的方法,可以使用cargo doc --open在本地查看。

3.6 数字比较

可以引入标准库中的std::cmp::Ordering 类型进行二值比较操作,该类型也是一个枚举类型,成员:

Less, Greater, Equal

可以使用match表达式对于比较结果进行操作,mathc表达式有多个分支组成,一个分支包含一个模式(pattern).

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

但是需要注意的是,rust语言是一个静态强类型语言,对于不同类型间的比较必须进行显式的类型转换。guess是String,secret_num是数字类型,所以必须把String转化为数字类型。

let guess: i32 = guess.trim().parse()
    .expect("It's not a number");

在这里声明了一个影子变量来覆盖原有的变量,通常用于需要类型转换的情景,而不是创建两个变量。对于字符串,先使用trim()减去空白字符,然后使用parse()方法转换为i32类型。与之前的输入操作一样,该操作也易发生错误,所以返回一个Result变量,需要使用expect()函数进行处理。

为了让输入错误后程序继续执行,可以将expect函数转换为进一步的处理:将 expect 调用换成 match 语句,是从遇到错误就崩溃转换到真正处理错误的惯用方法。须知 parse返回一个 Result 类型,而 Result 是一个拥有 Ok 或 Err 成员的枚举。这里使用的 match 表达式,和之前处理 cmp 方法返回 Ordering 时用的一样。

let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

3.7 使用循环

loop关键字创建一个无限循环,需要手动设置循环终止条件。

3.8 通配符

_可以用来指代一个不需要使用的变量

PreviousActix-web 基本使用Next结构体的使用

Last updated 5 years ago

Was this helpful?