首页 > 其他分享 >RUST

RUST

时间:2022-11-09 16:56:47浏览次数:31  
标签:guess number let fn println main RUST

Hello,World

基础指令
mkdir(新建目录)
cd(进入文件夹)
rustc xxxx.rs(关于该代码,创建一个可运行文件(二进制代码)。(rustc并不常用)

.\xxxx.exe(运行该文件)

示例(Hello World)

fn main()
{
    println!("hello world!");
}
  1. “!”说明用的是宏而不是普通函数,并且宏并不总是遵循与函数相同的规则
  2. 编译(code)和运行(git)是彼此独立的步骤, Rust 是一种 预编译静态类型语言

Hello,Cargo

  1. Cargo 是 Rust 的构建系统和包管理器。(构建代码、下载依赖库并编译这些库。)
  2. Cargo.toml
  3. Cargo new hello_world
  • Cargo build(生成可执行文件target/debug/hello_cargo)——(命令)./target/debug/hello_world
  • Cargo run(同时编译并运行生成的可执行文件)
  • 有别于将构建结果放在与源码相同的目录,Cargo 会将其放到 target/debug 目录。
  1. Cargo check (检查代码确保其可以编译,但并不产生可执行文件)
  2. 当项目最终准备好发布时,可以使用 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}");
}
  1. String是一个标准库提供的字符串类型,它是 UTF-8 编码的可增长文本块。
  2. 关联函数是针对类型实现的,它是创建类型实例的惯用函数名。
  3. Result是一种枚举类型(通常也写作enum),其成员为Ok(内部包含成功时产生的值),Err(包含失败的前因后果),Result的实例有expect办法。
  4. 如果 io::Result 实例的值是 Errexpect 会导致程序崩溃,并显示当做参数传递给 expect 的信息。如果 read_line 方法返回 Err,则可能是来源于底层操作系统错误的结果。如果 Result 实例的值是 Okexpect 会获取 Ok 中的值并原样返回。在本例中,这个值是用户输入到标准输入中的字节数。(由于希望程序在出现问题时立即崩溃,所以直接使用 expect。)
  5. Cargo.toml中[dependencies] 片段告诉 Cargo 本项目依赖了哪些外部 crate 及其版本。在[dependencies]片段标题之下,指定所需要的依赖。
  6. 当将来构建项目时,Cargo 会发现 Cargo.lock 已存在并使用其中指定的版本,而不是再次计算所有的版本,项目会持续使用 0.8.3 直到你显式升级。
  7. 当你需要升级 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}");

}
  1. Rng 是一个 trait,它定义了随机数生成器应实现的方法,想使用这些方法的话,此 trait 必须在作用域中。
  2. 范围表达式: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!"), 
	} 
}
  1. 一个 match 表达式由 分支(arms) 构成。一个分支包含一个 模式pattern)和表达式开头的值与分支模式相匹配时应该执行的代码。
  2. match 表达式会在第一次成功匹配后终止,因为该场景下没有检查最后一个分支的必要。若不匹配,顺序向下。
  3. 由于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!"), 
	}
  1. String 实例的 trim 方法会去除字符串开头和结尾的空白字符,我们必须执行此方法(去除空白字符)才能将字符串与 u32 比较。
  2. 字符串的 parse 方法将字符串转换成其他类型。我们需要告诉 Rust 具体的数字类型,这里通过 let guess: u32 指定。(parse 方法只有在字符逻辑上可以转换为数字的时候才能工作所以非常容易出错,如果有非数字的话,例如:A、%)
  3. 如果 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!"), 
		} 
	} 
}
  1. 用户可以使用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; 
			} 
		}
	} 
}
  1. 一个break语句,当猜对数字后退出循环。
  2. 此程序中退出循环也意味着退出程序,因为循环是 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--
  1. 忽略非数字的猜测并重新请求数字而不是让程序崩溃
  2. 如果 parse 能够成功的将字符串转换为一个数字,它会返回一个包含结果数字的 Ok,从而得到num。
  3. 如果 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,你不能改变变量的类型。


数据类型

  1. 两类数据类型子集:标量(scalar):整型、浮点型、布尔类型和字符类型;复合(compound):元组、数组。
  2. 整型一个有符号(ixx)的变体可以储存包含从 -(2^n - 1) 到 2^n - 1 - 1 在内的数字,无符号(uxx)的变体可以储存从 0 到 2^n - 1 的数字,当数字需要考虑前缀的时候,数字以+、-号为前缀。isize 和 usize 类型依赖运行程序的计算机架构:64 位架构上它们是 64 位的, 32 位架构上它们是 32 位的。
  3. 浮点型:f64、f32(双精度、单精度),另外,所有的浮点型都是有符号的。
  4. 运算Rust 中的所有数字类型都支持基本数学运算:加法、减法、乘法、除法和取余。整数除法会向下舍入到最接近的整数。
  5. 布尔型:Rust 中的布尔类型使用 bool 表示。Rust 中的布尔类型有两个可能的值:true 和 false
  6. 字符类型:Rust的 char 类型是语言中最原生的字母类型。我们用单引号声明 char 字面量,而与之相反的是,使用双引号声明字符串字面量。
  7. 复合类型:元组和数组。
  • 元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增大或缩小。我们使用包含在圆括号中的逗号分隔的值列表来创建一个元组。元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。例如`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 分成了三个不同的变量,xy 和 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! 语句。

函数

  1. fn,他用于定义新函数。(我们在Rust 中通过输入 fn 后面跟着函数名和一对圆括号来定义函数。大括号告诉编译器哪里是函数体的开始和结尾)
  2. Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行。
  3. 我们可以定义拥有 参数parameters)的函数,参数是特殊变量,是函数签名的一部分。当函数拥有参数(形参)时,可以为这些参数提供具体的值(实参)。在函数签名中,必须 声明每个参数的类型。
  4. 语句Statements)是执行一些操作但不返回值的指令。表达式(Expressions)计算并产生一个值。
  5. 表达式会计算出一个值。表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。
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;//语句不返回任何值
}

  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 整型,若他们类型不同则会产生错误。

  • 循环
  • looploop 关键字告诉 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

相关文章

  • Rust语言学习
    参考Rust教程vim插件rust语言官网......
  • source insight 使用Uncrustify来格式化代码
    参考 ​​http://myswirl.blog.163.com/blog/static/5131864220106295590650/​​1.下载 ​​http://sourceforge.net/projects/uncrustify/​​,下载解压......
  • 012 Rust 异步编程,在 async 块中使用?
    在Rust异步编程中能否像在同步编程中一样使用问号呢?我们来试试。示例源码[dependencies]futures="0.3"配置文件usefutures;asyncfnfoo()->Result<(),String>{"f......
  • 013 Rust 异步编程,Send trait 相关
    asyncfnFuture是否为Send的取决于是否在.await点上保留非Send类型。编译器尽其所能地估计值在.await点上的保存时间。示例源码usestd::rc::Rc;#[derive(Default)]struct......
  • 011 Rust 异步编程,返回错误
    在Rust异步块中,当发生返回错误的时,会是怎么样的呢?本节就这个知识点进行讲解。示例源码usefutures;asyncfnfoo(){"foo"}fnmain(){futures::executor::block_on......
  • 010 Rust 异步编程,使用 select 宏的条件
    使用select宏select中使用的Future必须实现Unpintrait和FusedFuturetrait。必须实现unpin的原因是,select中使用的future不是按值获取的,而是按照可变引用获取的,通过不获取f......
  • rustyline 介绍
    最近在写区块链的教学demo的时候,需要编写一个cli客户端和用户进行交互,最终找到了rustyline,按照官方的例子敲了一遍,觉得使用起来非常的舒适,因此推荐给大家。示例配置文件修改......
  • 009 Rust 异步编程,select 宏中的使用 default 和 complete
    说明在前一节,我们简单介绍了select宏。其实在select宏中,还可使用default和complete,前者表示没有分支完成,而后者则表示所有的分支都已经完成并且不会再取得进展的情况。示例......
  • 008 Rust 异步编程,select 宏介绍
    select宏select宏也允许并发的执行Future,但是和join、try_join不同的是,select宏只要有一个Future返回,就会返回。示例源码usefutures::{select,future::FutureExt,pin_mut......
  • 007 Rust 异步编程,通过 join 执行 Future
    前言在之前我们主要介绍了通过await和block_on执行Future,但是这两种方式实际上都是顺序执行的方式。.await是在代码块中按顺序执行,会阻塞后面的代码,但是此时会让出线程;block......