Hello,World
基础指令
mkdir(新建目录)
cd(进入文件夹)
rustc xxxx.rs(关于该代码,创建一个可运行文件(二进制代码)。(rustc并不常用)
.\xxxx.exe(运行该文件)
示例(Hello World)
fn main()
{
println!("hello world!");
}
- “!”说明用的是宏而不是普通函数,并且宏并不总是遵循与函数相同的规则
- 编译(code)和运行(git)是彼此独立的步骤, Rust 是一种 预编译静态类型语言
Hello,Cargo
- Cargo 是 Rust 的构建系统和包管理器。(构建代码、下载依赖库并编译这些库。)
- Cargo.toml
- Cargo new hello_world
- Cargo build(生成可执行文件target/debug/hello_cargo)——(命令)./target/debug/hello_world
- Cargo run(同时编译并运行生成的可执行文件)
- 有别于将构建结果放在与源码相同的目录,Cargo 会将其放到 target/debug 目录。
- Cargo check (检查代码确保其可以编译,但并不产生可执行文件)
- 当项目最终准备好发布时,可以使用
cargo build --release
来优化编译项目。这会在 target/release 而不是 target/debug 下生成可执行文件。这些优化可以让 Rust 代码运行的更快,不过启用这些优化也需要消耗更长的编译时间。(release也用于测试代码运行时间)
guessing_game
读取数字
use std::io;//将 io(输入\输出库)引入当前作用域。
fn main() //声名(无参数){
//提示用户
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new();//创建了一个可变变量,当前它绑定到一个新的String空实例上
//接受用户输入
io::stdin()
.read_line(&mut guess) //调用read_line方法从标准输入句柄获取用户输入
.expect("Failed to read line");//枚举
println!("You guessed: {guess}");
}
- String是一个标准库提供的字符串类型,它是 UTF-8 编码的可增长文本块。
- 关联函数是针对类型实现的,它是创建类型实例的惯用函数名。
- Result是一种枚举类型(通常也写作enum),其成员为Ok(内部包含成功时产生的值),Err(包含失败的前因后果),Result的实例有expect办法。
- 如果
io::Result
实例的值是Err
,expect
会导致程序崩溃,并显示当做参数传递给expect
的信息。如果read_line
方法返回Err
,则可能是来源于底层操作系统错误的结果。如果Result
实例的值是Ok
,expect
会获取Ok
中的值并原样返回。在本例中,这个值是用户输入到标准输入中的字节数。(由于希望程序在出现问题时立即崩溃,所以直接使用expect
。) - Cargo.toml中
[dependencies]
片段告诉 Cargo 本项目依赖了哪些外部 crate 及其版本。在[dependencies]
片段标题之下,指定所需要的依赖。 - 当将来构建项目时,Cargo 会发现 Cargo.lock 已存在并使用其中指定的版本,而不是再次计算所有的版本,项目会持续使用
0.8.3
直到你显式升级。 - 当你需要升级 crate 时,Cargo 提供了这样一个命令:
update
(Cargo 默认只会寻找大于0.8.3
而小于0.9.0
的版本。)
生成随机数
use std::io;
use rand::Rng;//新增
fn main() {
println!("Guess the number!");
let_secret_number = rand::thread_rng().gen_range(1..=100);//`rand::thread_rng` 函数提供实际使用的随机数生成器。`gen_range` 方法获取一个范围表达式(range expression)作为参数,并生成一个在此范围之间的随机数。
println!("The secret number is: {secret_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}");
}
Rng
是一个 trait,它定义了随机数生成器应实现的方法,想使用这些方法的话,此 trait 必须在作用域中。- 范围表达式:start..=end。
比较
use rand::Rng;
use std::cmp::Ordering;//一个枚举,成员为Less\Greater\Equal(比较两个值可能出现的结果)
use std::io;
fn main()
{ // --snip--
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {//比较guess和secret_number
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
- 一个
match
表达式由 分支(arms) 构成。一个分支包含一个 模式(pattern)和表达式开头的值与分支模式相匹配时应该执行的代码。 match
表达式会在第一次成功匹配后终止,因为该场景下没有检查最后一个分支的必要。若不匹配,顺序向下。- 由于guess是字符类型(string),secret_number是数字类型,这会导致代码发生错误(Rust不会比较字符串类型和数字类型,所以需要转换字符串类型)
类型转换
// --snip--
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
//新代码新建了一个guess隐藏(这允许我们复用变量的名字)了之前的guess,这种用法常用于转换值类型
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
String
实例的trim
方法会去除字符串开头和结尾的空白字符,我们必须执行此方法(去除空白字符)才能将字符串与u32
比较。- 字符串的
parse
方法将字符串转换成其他类型。我们需要告诉 Rust 具体的数字类型,这里通过let guess: u32
指定。(parse
方法只有在字符逻辑上可以转换为数字的时候才能工作所以非常容易出错,如果有非数字的话,例如:A、%) - 如果
parse
不能从字符串生成一个数字,返回一个Result
的Err
成员时,expect
会使游戏崩溃并打印附带的信息。
循环
// --snip--
println!("The secret number is: {secret_number}");
loop {
println!("Please input your guess."); //loop关键字创建了一个无限循环。
// --snip--
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
}
- 用户可以使用ctrl+c跳出无限循环,也可以利用parse识别到字母时,致使程序崩溃来跳出循环。
跳出循环
//--snip--
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
- 一个break语句,当猜对数字后退出循环。
- 此程序中退出循环也意味着退出程序,因为循环是 main的最后一部分。
处理无效输入
// --snip--
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
//将expect调用换成match语句,以从遇到错误就崩溃转换为处理错误。
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue, //进入下一个循环
};
println!("You guessed: {guess}");
// --snip--
- 忽略非数字的猜测并重新请求数字而不是让程序崩溃
- 如果
parse
能够成功的将字符串转换为一个数字,它会返回一个包含结果数字的Ok
,从而得到num。 - 如果
parse
不能将字符串转换为一个数字,它会返回一个包含更多错误信息的Err
从而跳过该循环(重新请求数字)。
完整代码
guessing_game
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
常见编程概念
Rust 是 静态类型(statically typed)语言,也就是说在编译时就必须知道所有变量的类型。
变量与可变性
//False
fn main() {
let x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
//true
fn main() {
let mut x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
1.变量默认不可改变。但是可以重复定义同一个参数名,这称为隐藏
。(Rust 编译器保证,如果声明一个值不会变,它就真的不会变,所以你不必自己跟踪它。这意味着你的代码更易于推导。)
2. 可以在命令面前增加一个mut
来使其可变.
3. 隐藏
可以让一个变量在不同步骤分别表示不同的类型,如果使用mut,你不能改变变量的类型。
数据类型
- 两类数据类型子集:标量(scalar):整型、浮点型、布尔类型和字符类型;复合(compound):元组、数组。
- 整型一个有符号(ixx)的变体可以储存包含从 -(2^n - 1) 到 2^n - 1 - 1 在内的数字,无符号(uxx)的变体可以储存从 0 到 2^n - 1 的数字,当数字需要考虑前缀的时候,数字以+、-号为前缀。isize 和 usize 类型依赖运行程序的计算机架构:64 位架构上它们是 64 位的, 32 位架构上它们是 32 位的。
- 浮点型:f64、f32(双精度、单精度),另外,所有的浮点型都是有符号的。
- 运算Rust 中的所有数字类型都支持基本数学运算:加法、减法、乘法、除法和取余。整数除法会向下舍入到最接近的整数。
- 布尔型:Rust 中的布尔类型使用
bool
表示。Rust 中的布尔类型有两个可能的值:true
和false
。 - 字符类型:Rust的
char
类型是语言中最原生的字母类型。我们用单引号声明char
字面量,而与之相反的是,使用双引号声明字符串字面量。 - 复合类型:元组和数组。
- 元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增大或缩小。我们使用包含在圆括号中的逗号分隔的值列表来创建一个元组。元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。例如`let tup: (i32, f64, u8) = (500, 6.4, 1);
- 为了从元组中获取单个值,可以使用模式匹配(pattern matching)来解构(destructure)元组值。
fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {y}");
}
- 程序首先创建了一个元组并绑定到
tup
变量上。接着使用了let
和一个模式将tup
分成了三个不同的变量,x
、y
和z
。这叫做 解构(destructuring),因为它将一个元组拆成了三个部分 - 我们也可以使用点号(
.
)后跟值的索引来直接访问它们。
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
- 不带任何值的元组有个特殊的名称,叫做 单元(unit) 元组。这种值以及对应的类型都写作
()
,表示空值或空的返回类型。如果表达式不返回任何其他值,则会隐式返回单元值。 - 数组类型:数组中的每个元素的类型必须相同。Rust 中的数组与一些其他语言中的数组不同,Rust中的数组长度是固定的。
fn main() { let a = [1, 2, 3, 4, 5]; }
- 可以使用索引来访问数组的元素
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
- 程序在索引操作中使用一个无效的值时导致 运行时 错误。程序带着错误信息退出,并且没有执行最后的
println!
语句。
函数
fn
,他用于定义新函数。(我们在Rust 中通过输入fn
后面跟着函数名和一对圆括号来定义函数。大括号告诉编译器哪里是函数体的开始和结尾)- Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行。
- 我们可以定义拥有 参数(parameters)的函数,参数是特殊变量,是函数签名的一部分。当函数拥有参数(形参)时,可以为这些参数提供具体的值(实参)。在函数签名中,必须 声明每个参数的类型。
- 语句(Statements)是执行一些操作但不返回值的指令。表达式(Expressions)计算并产生一个值。
- 表达式会计算出一个值。表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。
fn main() {
let y = {
let x = 3;
x + 1 //不加分号
};
println!("The value of y is: {y}");
}
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1;//语句不返回任何值
}
- 函数可以向调用它的代码返回值。我们并不对返回值命名,但要在箭头(
->
)后声明它的类型。
注释:在 Rust 中,惯用的注释样式是以两个斜杠开始注释,并持续到本行的结尾。对于超过一行的注释,需要在每一行前都加上 //
// hello, world
控制流
if
表达式
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
- 代码中的条件 必须 是
bool
值。
fn main() {
let number = 3;
if number {
println!("number was three");
}
}
应改为:
fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}
if
是一个表达式,我们可以在let
语句的右侧使用它。
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");//The value of number is: 5
}
if
分支和else
分支的结果都是i32
整型,若他们类型不同则会产生错误。
- 循环
loop
:loop
关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止(比如ctrl+c)。可以选择在一个循环上指定一个 循环标签(loop label),然后将标签与break
或continue
一起使用,使这些关键字应用于已标记的循环而不是最内层的循环。- while:当条件为真,执行循环。当条件不再为真,调用
break
停止循环。 - for:类似while(使用
for
循环的话,就不需要惦记着在改变数组元素个数时修改其他的代码了) - 两种遍历:
//while
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
//while需要注意条件
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
//for
fn main() {
let a = [10, 20, 30, 40, 50];
//for不需要
for element in a {
println!("the value is: {element}");
}
}
标签:guess,number,let,fn,println,main,RUST From: https://www.cnblogs.com/1042959213-jxy/p/16874328.html