上海建设部门网站,哪个网站推广好,新网站如何做免费推广,沈阳男科女医生在第一节#xff08;20天学rust#xff08;一#xff09;和rust say hi#xff09;我们配置好了rust的环境#xff0c;并且运行了一个简单的demo——practice-01#xff0c;接下来我们将从示例入手#xff0c;学习rust的基础语法。 首先来看下项目结构#xff1a; 项目…在第一节20天学rust一和rust say hi我们配置好了rust的环境并且运行了一个简单的demo——practice-01接下来我们将从示例入手学习rust的基础语法。 首先来看下项目结构 项目结构
practice-01
├── Cargo.lock # Cargo 依赖版本锁定文件
├── Cargo.toml # Cargo 主要设置文件
└── src└── main.rs # Rust 程序入口项目的重点文件有两个Cargo.toml文件和main.rs。我们首先来看下practice-01的Cargo.toml
rust的灵魂——Cargo.toml
[package]
name practice-01
version 0.1.0
edition 2021# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
fast-str 1.0.0其实这里是一个极简的文件它用于管理项目的依赖项、编译选项和其他配置信息我们来看下完整的
[package]
name my_project
version 0.1.0
edition 2018[dependencies]
crate_name version[dev-dependencies]
dev_crate_name version[build-dependencies]
build_crate_name version[features]
feature_name [dependency_name/version][package] 用于指定包的元数据包括名称、版本和edition。名称是包的唯一标识符版本遵循语义化版本规范edition指定Rust编译器使用的版本。[dependencies] 用于指定项目的依赖项。每个依赖项由crate名称和版本号组成可以通过在 后面指定版本号或使用特定的版本约束来指定依赖项的版本。[dev-dependencies] 用于指定只在开发环境中使用的依赖项例如测试框架或代码检查工具。[build-dependencies] 用于指定在构建过程中需要的依赖项例如构建脚本或代码生成工具。[features] 用于定义项目的特性features特性是一组可选的依赖项可以通过在 后面列出依赖项的名称和版本号来指定。 Cargo.toml文件还可以包含其他配置项例如构建脚本、路径别名、工作空间设置等。这些配置项可以根据项目的需要进行自定义。 通过编辑和配置Cargo.toml文件可以管理Rust项目的依赖项、版本控制和构建过程。Cargo工具使用Cargo.toml文件来构建、测试和发布Rust项目使得项目的管理变得简单和方便。 更多信息可以参考rust官网文档cargo/Cargo.toml
接下来再看main.rs的代码我将逐行的解释下面代码
use std::io;fn main() {println!(Hello!);loop {let mut input String::new();io::stdin().read_line(mut input).expect(Failed to read input!);if input.contains(quit) {break;}i_say_what_u_say(input)}
}fn i_say_what_u_say(str: String) {print!({}, str)
}
use std::io;
这里有两个知识点use、::
use
在Rust中 use 关键字用于引入一个模块或类型的路径到当前作用域以便在代码中可以直接使用该模块或类型的名称而无需每次都写完整的路径。 use 关键字有两种常见的用法
引入模块可以使用 use 关键字来引入一个模块以便在当前作用域中直接使用模块中的项函数、结构体、枚举等。引入模块的语法是 use 模块路径 。 例如如果想在代码中使用 std::io::Result 可以使用 use 关键字引入该模块 use std::io::Result; 然后就可以在代码中直接使用 Result 而无需写完整的路径 std::io::Result 。引入类型可以使用 use 关键字来引入一个具体的类型以便在当前作用域中直接使用该类型的名称。引入类型的语法是 use 类型路径 。 例如如果想在代码中使用 std::io::Error 可以使用 use 关键字引入该类型 use std::io::Error; 然后就可以在代码中直接使用 Error 而无需写完整的路径 std::io::Error 。 需要注意的是 use 关键字只是将指定的模块或类型的路径引入到当前作用域并不会导入任何其他的项。如果想要导入模块中的所有项可以使用 use 模块路径::* 的语法。
如果你有Java或者Go的经验理解起来就很容易它类似于import的用法。如果不用use也行只不过在每次用到的时候都需要写全路径名。
::
在Rust中::是一个作用域解析运算符用于访问模块、结构体、枚举、常量、函数等定义在特定命名空间中的项。 下面是关::的一些用法和含义
访问模块中的项
mod my_module {pub fn my_function() {// 函数实现}}// 使用::来访问模块中的函数my_module::my_function();访问结构体和枚举中的项
struct MyStruct {my_field: i32,}// 使用::来访问结构体的字段let my_value MyStruct { my_field: 42 };println!({}, my_value.my_field);enum MyEnum {Variant,}// 使用::来访问枚举的变体let my_variant MyEnum::Variant;访问常量和函数
const MY_CONSTANT: i32 42;// 使用::来访问常量println!({}, MY_CONSTANT);fn my_function() {// 函数实现}// 使用::来访问函数my_function();需要注意的是::并不是一个特定于Rust的运算符它在其他编程语言中也有类似的用法。它的作用是帮助标识和访问特定命名空间中的项。 提到了::,还有个运算符就不得不提. 。
.
Rust中的 . 运算符用于访问结构体、枚举、模块和其他数据类型的字段、方法和关联常量。 . 运算符用法示例
struct Person {name: String,age: u32,
}impl Person {fn new(name: str, age: u32) - Person {Person {name: name.to_string(),age,}}fn say_hello(self) {println!(Hello, my name is {}, self.name);}
}fn main() {let person Person::new(Alice, 25);println!(Name: {}, person.name);println!(Age: {}, person.age);person.say_hello();
}rust的入口——main函数
fn main() main是整个程序的入口也是整个软件的灵魂。这个就不用多说了。
rust里的一等公民——i_say_what_u_say
fn i_say_what_u_say(str: String) {print!({}, str)
}这里我们定义了一个函数i_say_what_u_say。在Rust中函数是一种用于封装可执行代码的基本构建块。以下是关于Rust函数的介绍
函数定义
在Rust中函数的定义使用 fn 关键字后跟函数名称、参数列表和返回类型。函数体由一对花括号 {} 包围用于包含实际的代码逻辑。
fn add(a: i32, b: i32) - i32 {let sum a b;sum
}上述代码定义了一个名为 add 的函数它接受两个 i32 类型的参数 a 和 b 并返回一个 i32 类型的结果。函数体中计算了 a 和 b 的和并将其作为函数的返回值。
函数调用
要调用一个函数只需使用函数名称后跟参数列表并使用圆括号 () 包围参数。
let result add(3, 5);
println!(Result: {}, result);上述代码调用了之前定义的 add 函数传递参数 3 和 5 。函数的返回值被存储在 result 变量中并通过 println! 宏打印出来。
函数参数和返回值
Rust函数可以有多个参数并且每个参数都需要指定类型。函数可以有一个返回值其类型在函数定义中使用 - 符号指定。如果函数没有返回值可以使用 () 表示空元组类型。
fn greet(name: str) {println!(Hello, {}!, name);
}fn multiply(a: i32, b: i32) - i32 {a * b
}// 通过元组可以包含多个返回值
fn multi_result(a:i32, b:i32) - (i32,i32){(a,b)
}上述代码展示了两个函数的例子。 greet 函数接受一个名为 name 的字符串引用参数并没有返回值。 multiply 函数接受两个 i32 类型的参数并返回它们的乘积。
函数作为一等公民
在Rust中函数是一等公民这意味着函数可以像其他值一样被传递、赋值和返回。可以将函数作为参数传递给其他函数也可以将函数作为返回值返回。
fn add(a: i32, b: i32) - i32 {a b
}fn subtract(a: i32, b: i32) - i32 {a - b
}fn operation(op: fn(i32, i32) - i32, a: i32, b: i32) - i32 {op(a, b)
}let result operation(add, 3, 5);
println!(Result: {}, result);上述代码展示了如何将函数作为参数传递给 operation 函数并在 operation 函数内部调用传递的函数。
println!(“Hello!”);
接下来我们再看下函数体的内容。 第一行就是println!(Hello!), 就很疑惑要说是函数吧为什么有个呢要说不是函数吧长得又太tm像了。 其实这是rust的另一个功能宏。
宏
Rust 中的宏Macro是一种元编程工具用于在编译时生成代码。宏允许你在编写 Rust 代码时创建自定义的代码片段以简化重复的代码增加代码的可读性和可维护性。宏可以接受不同数量和类型的参数并根据这些参数生成代码。 下面是一个使用 Rust 自定义宏的例子
macro_rules! greet {($name:expr) {println!(Hello, {}!, $name);};
}fn main() {greet!(Alice);greet!(Bob);
}在上面的例子中我们定义了一个名为 greet 的宏。这个宏接受一个表达式参数 $name 并生成一个打印欢迎消息的代码块。 在 main 函数中我们使用 greet! 宏两次分别传入不同的参数 Alice 和 Bob。在编译时宏会根据我们提供的参数展开并生成相应的代码。最终的输出将是
Hello, Alice!
Hello, Bob!再看println!(“Hello!”);
我们看下println!的定义
#[macro_export]
#[stable(feature rust1, since 1.0.0)]
#[cfg_attr(not(test), rustc_diagnostic_item print_macro)]
#[allow_internal_unstable(print_internals)]
macro_rules! print {($($arg:tt)*) {{$crate::io::_print($crate::format_args!($($arg)*));}};
}上面的代码实际上等同于 println!({},Hello!);std::io::_print(std::format_args!({},Hello!));这样是不是就清楚多了
loop
Rust提供了几种不同的循环语句用于重复执行代码块loop是rust的循环实现的一种方式
loop 循环
loop 循环是一个无限循环它会无限次地执行一个代码块直到遇到 break 关键字才会退出循环。
loop {// 无限循环的代码块// 可以使用 break 关键字来退出循环break;
}在 loop 循环中你可以使用 break 关键字来手动退出循环。这通常在满足某个条件时使用。
while 循环
while 循环会在满足给定条件的情况下重复执行一个代码块。
let mut i 0;
while i 5 {// 循环的代码块i 1;
}在 while 循环中首先会判断条件是否为真如果为真则执行循环体内的代码块然后再次判断条件。如果条件为假则退出循环。
for 循环
for 循环用于遍历一个集合或者一个范围内的元素并执行相应的代码块。
let numbers vec![1, 2, 3, 4, 5];
for number in numbers {// 循环的代码块println!({}, number);
}在 for 循环中你需要提供一个可迭代的集合或者一个范围表达式。在每次循环迭代中变量 number 会依次赋值为集合中的元素并执行循环体内的代码块。 Rust还提供了其他一些循环相关的关键字和语法如 continue 关键字用于跳过当前循环迭代 break 关键字用于退出循环以及循环标签loop label用于在嵌套循环中指定退出的位置等。
let mut input String::new();
这行Rust代码 let mut input String::new(); 的含义是创建一个可变的空字符串变量 input 。 具体解释如下
let Rust中用于声明变量的关键字。mut 表示变量是可变的mutable可以在后续的代码中修改其值。input 变量名可以根据需要进行命名。String::new() 调用了 String 类型的 new() 函数用于创建一个新的空字符串对象。 这行代码的作用是创建一个可变的字符串变量 input 并将其初始化为空字符串。这样我们可以在后续的代码中使用 input 变量来存储用户输入或其他字符串数据。 这里重点介绍一个点 mut
mut
mut 关键字用于声明可变变量mutable variable。使用 mut 关键字可以将一个变量标记为可变允许在后续的代码中修改其值。 那么不适用mut会怎么样呢
error[E0596]: cannot borrow input as mutable, as it is not declared as mutable-- src/main.rs:9:24|
9 | .read_line(mut input)| ^^^^^^^^^^ cannot borrow as mutable|
help: consider changing this to be mutable|
7 | let mut input String::new();|
给出了一个编译错误并且给了修复方案那就是在变量声明的时候加上mut, 那么是为什么呢 这里且卖一个关子如果有等不及的可以看我另一篇博文rust怎么搞的这么简单的代码也报“borrow of moved value“。
变量类型
这里我们定义了String类型的变量那么rust中还有哪些常用类型呢
整数类型Integer Types 整数类型用于表示整数值。在Rust中整数类型有多种包括有符号整数和无符号整数分别用 i 和 u 前缀表示后面跟上整数的位数。
let number: i32 42;
let unsigned_number: u64 100;浮点数类型Floating-Point Types 浮点数类型用于表示带有小数部分的数值。在Rust中浮点数类型有两种分别是 f32 和 f64 分别表示单精度浮点数和双精度浮点数。
let float_number: f32 3.14;
let double_number: f64 3.14159265359;布尔类型Boolean Type 布尔类型用于表示真或假的值。在Rust中布尔类型有两个可能的值即 true 和 false 。
let is_true: bool true;
let is_false: bool false;字符类型Character Type 字符类型用于表示单个Unicode字符。在Rust中字符类型使用单引号 表示。
let character: char A;数组类型Array Type 数组类型用于存储固定大小的元素序列。在Rust中数组的大小是在编译时确定的并且所有元素的类型必须相同。
let array: [i32; 3] [1, 2, 3];元组类型Tuple Type 元组类型用于存储多个不同类型的值。在Rust中元组使用圆括号 () 表示。
let tuple: (i32, f64, char) (42, 3.14, A);引用类型Reference Type 引用类型用于引用其他变量的值而不是拥有自己的所有权。在Rust中引用使用 符号表示。
let value: i32 42;
let reference: i32 value;切片类型Slice Type 切片类型用于引用数组或向量的一部分数据。在Rust中切片使用 [T] 表示。
let array: [i32; 5] [1, 2, 3, 4, 5];
let slice: [i32] array[..3];字符串类型String Type 字符串类型用于存储文本数据。在Rust中字符串类型由标准库提供使用 String 表示。
let string: String String::from(Hello, Rust!);向量类型Vector Type 向量类型用于存储可变大小的元素序列。在Rust中向量由标准库提供使用 VecT 表示。
let mut vector: Veci32 Vec::new();
vector.push(1);
vector.push(2);
vector.push(3);函数类型Function Type 函数类型用于定义函数。在Rust中函数类型由函数的参数类型和返回类型组成。
fn add(a: i32, b: i32) - i32 {a b
}结构体类型Struct Type 结构体类型用于自定义复杂的数据结构。在Rust中结构体使用 struct 关键字定义。
struct Person {name: String,age: u32,
}let person Person {name: String::from(Alice),age: 25,
};枚举类型Enum Type 枚举类型用于定义具有不同变体的类型。在Rust中枚举使用 enum 关键字定义。
enum Color {Red,Green,Blue,
}let color: Color Color::Red;io::stdin() io::stdin().read_line(mut input).expect(Failed to read input!);这段代码的作用是从标准输入读取一行输入并将其存储到一个可变的字符串变量 input 中。下面是对代码的解释
io::stdin() 这是一个函数调用返回一个标准输入的句柄handle用于从标准输入读取数据。.read_line(mut input) 这是对标准输入句柄调用的方法用于读取一行输入。 mut input 表示将输入存储到一个可变的字符串变量 input 中。 mut 表示传递一个可变引用以便在方法内部修改变量的值。.expect(Failed to read input!)这是一个错误处理方法。如果读取输入时发生错误会触发一个panic并打印出错误信息Failed to read input!。
if input.contains(“quit”) if input.contains(quit) {break;}这段代码的作用是检查字符串变量 input 中是否包含子字符串quit。如果包含则执行 break 语句跳出当前循环。这里重点学习下if的语法
条件判断
Rust中的条件判断语法使用 if 和 else 关键字来实现。下面是条件判断的语法示例和实际例子
if condition {// 当条件为真时执行的代码块
} else if condition2 {// 当条件2为真时执行的代码块
} else {// 当以上条件都不满足时执行的代码块
}示例代码
fn main() {let number 10;if number 0 {println!(The number is positive);} else if number 0 {println!(The number is negative);} else {println!(The number is zero);}
}最后一句i_say_what_u_say(input) 再前面函数位置已经介绍过了就不做过多介绍。至此我们学习了rust项目的基本目录结构、函数的定义、分支语法循环、条件和宏定义。掌握了这些基础就能写出简单的rust程序啦。
这里留一个课后作业写一个斐波那契函数Leetcode。
关注我学习rust不迷路