Rust基础知识

admin 2024年4月22日07:29:00评论2 views字数 14576阅读48分35秒阅读模式

一年终于更新了

Rust基础知识

Rust学习计划表

1. 环境搭建

2. 写个hello word

3. 学学基础

点击蓝字关注我哦~

Rust的代码组织

  • 代码组织主要包括:
    • 哪些细节可以暴露,哪些细节是私有的
    • 作用域内哪些名称有效

私有边界

Rust中所有的条目(函数、方法、Struct、enum、模块、常量)默认是私有的 模块不仅可以组织代码,还可以定义私有边界 如果想把函数或struct等设为私有,可以将它放到某个模块中 父级模块无法访问子级模块中的私有条目 子模块里可以使用所有祖先模块中的条目

pub关键字

使用pub关键字来将某些条目标记为公共的 只有标记为公共的,其他代码才可以使用,私有的条目只有同级作用域可以用

use关键字

可以使用use关键字将路径导入到作用域内,仍需遵循私有性原则 引入规则:

  • 函数:将函数的父级模块引入作用域(指定到父级)
  • struct,enum,其他:指定完整路径(指定到本身)
  • 同名条目:指定到父级
mod front_of_house{
 pub mod hosting{
  pub fn add_to_waitlist(){}
 }
}
// 使用绝对路径
//use crate::front_of_house::hosting;
// 使用相对路径
use front_of_house::hosting;
use std::collectings::Hashmap;
pub fn eat_at_restaurant(){
 hosting::add_to_waitlist();
 let mut map = HashMap::new();
 map.insert(1,2);
}

as关键字

as关键字可以为引入的路径指定本地的别名

use std::fmt::Result;
use std::io::Result as IoResult;

fn f1()-> IoResult{
 
}

使用pub use重新导出名称

使用use将路径名称导入到作用域后,该名称在此作用域内是私有的 pub use:重导出

  • 将条目引入作用域
  • 该条目可以被外部代码引入到它们的作用域
pub use std::fmt::Result;

使用嵌套路径清理大量的use语句

如果使用同一个包或模块下的多个条目

use std::io;
use std::fmt;

可以使用嵌套路径在同一行内将上述条目进行引入

  • 路径相同的部分::{路径差异的部分,多个之间用逗号分隔},self表示{}前的路径,如std::io = std::io{self}
use std::{io,fmt}

通配符*

使用*可以把路径中所有的公共条目都引入到作用域

use std::*

注意:谨慎使用 应用场景:

  • 测试:将所有被测试代码导入到test模块
  • 有时被用于预导入模块

使用外部包

  1. Cargo.toml添加依赖的包(package),Cargo会自动去https://cratrs.io/ 网站去下载对应的依赖文件
  2. use将特定 条目引入到作用域 在cargo.toml文件的[dependencies]中添加所需导入的包名称及版本
  3. Rust基础知识

  4. vscode会自动下载对应的版本,并提示是否有最新的版本
  5. Rust基础知识

  6. 标准库std也被当作外部包,但是不需要在cargo.toml中添加包含std,需要使用use将std中的特定条目引入当前作用域

如果下载特别慢或者下载失败,可以使用命令行下载

在命令行中输入cargo build命令,会出现如下的报错:Blocking waiting for file lock on package cache 

Rust基础知识

 进入cargo的安装目录,查看隐藏文件,将.package-cache文件删除

Rust基础知识

然后再允许cargo build命令即可重新下载

添加国内镜像源

进入cargo所在文件夹,创建config文件 添加如下的内容

[source.crates-io]
registry = "http://github.com/rust-lang/crates.io-index"

replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
[net]
git-fetch-with-cli = true
[http]
//解决SSL报错问题
check-revoke = false

然后重新build即可

rust模块系统

Rust 提供了一系列功能,可帮助你管理和组织代码。这些功能称为“Rust 模块系统”。系统由箱(Crate)、模块(Module)、路径(Path)和工具组成,以与那些项结合使用。

  • package(包):Cargo的特性,让你构建、测试、共享Crate
  • Crate(单元包):一个模块树,它可以产生一个library(库)或可执行文件
    • Rust Crate是一个编译单元。它是 Rust 编译器可以运行的最小代码段。Crate中的代码一起编译以创建二进制可执行文件或库。在 Rust 中,仅将Crate编译为可重复使用的单元。Crate包含具有隐式未命名顶级模块的 Rust 模块的层次结构。
  • Module(模块)、Use :让你控制代码的组织、作用域、私有路径
    • Rust 模块通过让你管理箱内单个代码项的范围来帮助你组织程序。结合使用的相关代码项或项可以分组到相同模块中。递归代码定义可以跨越其他模块。
  • Path(路径):为struct、function或module等项命名的方式
    • 在 Rust 中,可以使用路径来命名代码中的项。例如,路径可以是一个数据定义(例如,矢量、代码函数,甚至是模块)。模块功能还可帮助你控制路径的隐私。可以指定可公开访问的代码部分和私有部分。通过该功能可以隐藏实现详细信息

Crate

Crate的类型

Crate一共有两种类型,一种是二进制文件,一种是library,及库文件

Crate Root:

  • 是源代码文件
  • Rust编译器从这里开始,组成你的Crate的根Module

一个Package

  • 一个Package只包含一个Cargo.toml,它描述了如何构建这些Crates
  • 只能包含0-1个 library crate
  • 可以包含任意数量的二进制文件(Binary crate)
  • 但是至少包含一个Crate(library或binary)
  • 一个package可以同时包含src/main.rs和src/lib.rs
    • 一个binary crate,一个library crate
    • 名称与package名相同
  • 一个package可以有多个binary crate:
    • 文件都放在src/bin
    • 每个文件都是单独的binary crate

rust package程序结构

以使用cargo new创建的程序结构进行分析:

文件结构

上面的命令运行后,会创建一个新的目录,目录名与项目名一致,目录结构如下

Rust基础知识

  • src下存放的程序源代码,所有源码文件后缀都是rs
    • cargo生成的main.rs在src目录下
  • 会初始化一个.gitignore的git仓库
  • 创建一个Cargo.toml的配置文件,是cargo的配置格式
  • Rust基础知识

    • name,项目名称
    • version,项目版本
    • authors,项目作者
    • edittion,使用的rust版本
    • [package] 是一个区域标题,表示下发的内容是用来配置package的
    • [dependencies],另一个区域的开始,会列出项目的依赖项
  • 在rust中,代码的包称作crate。
  • 顶层目录可以放置:README、许可证信息、配置文件和其他与程序源码无关的文件
  • src/main.rs:
    • binary crate 的crate root
    • crate名与package名相同
  • src/lib.rs:
    • package 包含一个library crate
    • library crate的crate root
    • crate名与package名相同
  • Cargo把crate root文件交给rustc来构建library或binary

文件命名

程序文件后缀名:rs 文件命名规范:hello_word.rs

代码缩进

在函数体中,大多数代码语句以分号 ; 结尾。Rust 按顺序依次处理这些语句。当代码语句不以分号结尾时,Rust 知道必须执行下一行代码才能完成起始语句。

为了帮助查看代码中的执行关系,请使用缩进。此格式可显示代码的组织方式以及揭示完成功能任务的步骤流程。起始代码语句从左边距缩进四个空格。当代码不以分号结尾时,要执行的下一行代码再缩进四个空格。

下面是一个示例:

fn main() {// 函数声明没有缩进
    // 函数体的第一步
        // 子步骤: 在第一步完成之前执行
    // 函数体的第二步
        // 子步骤A: 在第二步之前执行完成
        // 子步骤B: 在第二步之前执行完成
            // 子步骤1: 在子步骤B完成之前执行
    // 函数体中的第三步,依此类推...
}

Crate的作用

将相关功能组合到一个作用域内,便于在项目间进行共享

  • 防止命名冲突 例如 Rand crate,访问它的功能需要通过它的名字rand

Module

  • 在一个crate内,将代码进行分组
  • 增加可读性,易于复用
  • 控制项目(item)的私有性。public、private

定义module

可以控制作用域和私有性建立module:

  • mod 名称{}
  • module是可嵌套的
  • 可包含其它项(struct、enum、常量、trait、函数等)的定义
mod front_of_hose{
 mod hosting{
  fn add_to_waitlist(){}
  fn seat_at_table(){}
 }
 mod serving{
  fn take_order(){}
 }
}

Rust基础知识

将模块内容移动到其他文件

模块定义是,如果模块名后面是;而不是代码块

  • rust会从与模块同名的文件中加载内容
  • 模块树的结构不会变化例子 源代码
  • Rust基础知识

  • 拆分后
  • Rust基础知识

  • 随着模块逐渐变大,该技术可以让把模块的内容移动到其他文件中

path 路径

为了在Rust的模块中找到某个条目,需要使用路径 路径的两种形式:

  • 绝对路径:从 crate root开始,使用crate名或字面值crate
  • 相对路径:从当前模块开始,使用self,super或当前模块的标识符 路径至少由一个标识符组成,标识符之间使用::
mod front_of_hose{
 pub mod hosting{
  pub fn add_to_waitlist(){}
  fn seat_at_table(){}
 }
 mod serving{
  fn take_order(){}
 }
}
pub fn eat_at_restaurant(){
 creat::front_of_hose::hosting::add_to_waitlist()
 front_of_hose::hosting::add_to_waitlist()
}

super关键字

super关键字:用来访问父级模块路径中的内容,类似文件系统中的..

fn serve_order(){}
mod back_of_house{
 fn fix_incorrect_order(){
  cook_order();
  super::serve_order();
 }
 fn cook_order(){}
}

使用 Rust 箱和库

Rust 标准库 std 包含 Rust 程序中的基本定义和操作的可重复使用代码。该库拥有核心数据类型(例如 String 和 Vec<T>)的定义、Rust 基元的操作、常用宏函数的代码、对输入和输出操作的支持以及许多其他功能区域。

有数以万计的库和第三方箱可用于 Rust 程序,其中大部分可以通过 Rust 的第三方箱存储库 crates.io 进行访问。稍后你将了解如何从项目访问这些箱,但以下是编程练习中使用的一些箱:

  • std - Rust 标准库。在 Rust 练习中,你将会注意到以下模块:
    • std::collections - 集合类型的定义,如 HashMap
    • std::env - 用于处理环境的函数。
    • std::fmt - 控制输出格式的功能。
    • std::fs - 用于处理文件系统的功能。
    • std::io - 用于处理输入/输出的定义和功能。
    • std::path - 支持处理文件系统路径数据的定义和功能。
  • structopt - 用于轻松分析命令行参数的第三方箱。
  • chrono - 用于处理日期和时间数据的第三方箱。
  • regex - 用于处理正则表达式的第三方箱。
  • serde - 适用于 Rust 数据结构的序列化和反序列化操作的第三方箱。

默认情况下,std 库适用于所有 Rust 箱。若要访问箱或库中的可重复使用代码,请使用 use 关键字。通过 use 关键字,箱或库中的代码就会“进入范围”,这样你就可以访问程序中的定义和功能。标准库是在路径 std 的 use 语句中访问的,如 use std::fmt 所示。其他箱或库是通过其名称访问的,例如 use regex::Regex

使用 Cargo 创建和管理项目

虽然可以直接使用 Rust 编译器 (rustc) 来生成箱,但大多数项目都使用 Rust 生成工具和名为 Cargo 的依赖项管理器。

Cargo 可以为你做许多事情,包括:

  • 使用 cargo new 命令创建新的项目模板。
  • 使用 cargo build 编译项目。
  • 使用 cargo run 命令编译并运行项目。
  • 使用 cargo test 命令测试项目。
  • 使用 cargo check 命令检查项目类型。
  • 使用 cargo doc 命令编译项目的文档。
  • 使用 cargo publish 命令将库发布到 crates.io
  • 通过将箱的名称添加到 Cargo.toml 文件来将依赖箱添加到项目。

编译与运行rust程序

rustc

rustc只适合简单的rust程序编译和运行是单独的两个步骤:

  • 运行Rust程序之前必须先编译,命令未rustc 源文件名
    • 编译:rust main.rs,编译完成后会生成exe文件
  • 编译成功后,会生成一个二进制文件
    • 在windows系统上还会生成一个.pdb文件,里面包含调试信息
  • Rust是ahead-of-time编译的语言:
    • 可以先编译程序,然后把编译好的可执行文件交给别人运行(无需安装rust)
  • 运行:
    • windows:.main.exe
    • Linux:./main

Cargo

  • Cargo是Rust的构建系统和包管理工具
    • 构建代码、下载依赖的库、构建这些库
    • 安装rust的时候会自动安装好Cargo 如果创建项目时没有使用cargo,也可以把项目转化为使用cargo
  • 把源代码文件移动到src目录下
  • 在cargo.toml配置中添加相关的信息

使用cargo 创建项目

创建普通项目

cargo new 项目名

使用cargo构建library项目

cargo new 项目名 --lib

使用cargo构建项目

cargo build

创建可执行文件:targetdebughello_cargo或targetdebughello_cargo.exe(windows) 第一次运行cargo build 会在项目顶层目录生成cargo.lock文件

  • 该文件负责追踪项目依赖的精确版本
  • 不需要手动修改该文件

构建并运行cargo项目

cargo run

如果之前编译成功过,并且源码没有改变,那么就会直接运行二进制文件。如果没有编译过,或修改了源码,则会先编译成二进制文件,然后运行二进制文件。

Rust基础知识

使用cargo检查代码

cargo check

检查代码,确保能通过编译,但是不产生任何可执行文件

  • cargo check要比cargo build快得多
    • 编写代码的时候可以连续反复的使用cargo check检查代码,提高效率

编译发布版本

cargo build --release
  • 编译时会进行优化
    • 代码会运行的更快,但是编译时间会更长
  • 会在target/release而不是target/debug生成可执行文件
  • 存在两种配置:
    • 一个开发使用
    • 一个发布使用

特殊语句

debug语句

在上面的示例中,查找以下代码语句。代码的多个位置使用了该语句。

// Set the Debug flag so we can check the data in the output
#[derive(Debug)]

通过 #[derive(Debug)] 语法可以在代码执行期间查看某些在标准输出中无法查看的值。要使用 println! 宏查看调试数据,请使用语法 {:#?} 以可读的方式格式化数据。

{}参数的值替换

在 Rust Learn 模块课程中,我们经常使用参数列表调用 println! 宏,该参数列表包括使用大括号 {} 实例括起来的文本字符串和其他值。 println! 宏将文本字符串中的每个大括号 {} 实例替换为列表中下一个参数的值。示例:

fn main() {

    // 调用println!具有三个参数: 字符串,值,值

    println!("英文字母表的第一个字母是{},最后一个字母是{}."'A''Z');

}

Rust基础知识

我们使用三个参数调用 println! 宏:字符串、值和其他值。宏按顺序处理参数。文本字符串中的每个大括号 {} 实例都替换为列表中下一个参数的值。

rust 宏

todo! 宏

在 Rust 模块中练习时,你会注意到示例代码通常使用 todo! 宏。Rust 中的宏类似于采用可变数量的输入参数的函数。 todo! 宏用于标识 Rust 程序中未完成的代码。宏有助于原型制作,或者当你想要指示未完成的行为时。

下面是练习中如何使用 todo! 宏的示例:

fn main() {

    // 显示消息 “Hello,world!”

    todo!("使用println!() 宏显示消息");

}

编译使用todo!宏的代码时,编译器可能会返回一条需要查找已完成功能的紧急消息:

Rust基础知识

println!宏

main 函数执行一项任务。该函数调用在 Rust 中预定义的 println! 宏。 println! 宏需要一个或多个输入参数,这些参数会显示在屏幕或标准输出中。在示例中,我们将一个输入参数(即文本字符串“Hello, world!”)传递给宏

fn main() {

    // 我们的主要功能执行一项任务: 显示一条消息

    // println!在屏幕上显示输入 “Hello,world!”

    println!("Hello, world!");

}

Rust基础知识

println!()宏中可以使用{}占位符输出变量的内容,本质是调用了变量的Display方法,但是如果目标类型没有实现Display的方法,则不能使用{}占位符进行直接输出

Rust基础知识

可以修改为使用{:?}或{:#?}进行打印输出,但是要先在定义的目录类型前添加debug声明

//定义长方形的struct

#[derive(Debug)]
struct Rectangle{
    width: u32,
    length: u32,
}
println!("{:?}", rect);

Rust基础知识

rust中的函数

函数是执行特定任务的代码块。我们根据任务将程序中的代码分割成块。通过分割,代码变得更易于理解和维护。在为任务定义函数后,可以在需要执行相应任务时调用该函数。

每个 Rust 程序都必须有一个名为 main 的函数。 main 函数中的代码始终是 Rust 程序中运行的第一个代码。我们可以从 main 函数内部或从其他函数内部调用其他函数。

fn main() {
    println!("Hello, world!");
}

定义函数:fn main() {}

  • 没有参数,没有返回值 main函数很特别:它是每个rust可执行程序最先运行的代码 打印文本:println!("hello word");
  • rust的缩进是4个空格而不是tab
  • println!是一个rust macro(宏)
    • 如果是函数的话,就没有!
    • “hello word”是字符串,是println!的参数
    • 这行代码以;结尾

声明函数

要在 Rust 中声明函数,必须使用 fn 关键字。在函数名称后面,告知编译器函数需要多少形参或实参作为输入。参数在括号 () 内列出。函数体是执行函数任务的代码,在大括号 {} 内定义。最佳做法是将代码格式化,使函数体的左大括号紧跟在参数列表的括号后面。

  • Rust 函数的命名规范(snake case)
    • 所有的字母都是小写的,单词之间使用下划线分开
fn main() {
    println!("Hello, world!");
    goodbye();
}

fn goodbye() {
    println!("Goodbye.");
}

我们使用函数名称以及括号中的输入参数来调用函数。如果函数没有任何输入参数,则将括号留空。在示例中,main 和 goodbye 函数都没有输入参数。

你可能已经注意到,我们在定义 main 函数后,定义了 goodbye 函数。我们本可以在定义 main 之前定义 goodbye 函数。Rust 不在意文件中函数的定义位置,只要在文件中的某处定义了函数即可。

查看签名

函数声明的第一部分称为函数签名。

示例中 goodbye 函数的签名具有以下特征:

  • fn:Rust 中的函数声明关键字。
  • goodbye:函数名称。
  • (message: &str):函数的实参或形参列表。一个指向字符串数据的指针应作为输入值。
  • -> bool:箭头指向此函数将始终返回的值类型。

goodbye 函数接受一个字符串指针作为输入并输出一个布尔值。

函数参数

如果函数具有输入参数,请命名每个参数并在函数声明的开头指定数据类型。由于参数的命名方式与变量类似,因此可以访问函数体中的参数。

  • 函数的签名里,必须指明每个参数的类型
  • 多个参数之间使用逗号分开
fn  add(x:i32, y:i32) ->i32{
    x+y
}

让我们修改 goodbye 函数,以将指向某些字符串数据的指针作为输入参数。

fn goodbye(message: &str) {
    println!("n{}", message);
}

fn main() {
    let formal = "Formal: Goodbye.";
    let casual = "Casual: See you later!";
    goodbye(formal);
    goodbye(casual);
}

通过使用两个不同的参数值从 main 函数调用声明的函数来对其进行测试,然后检查输出:

Rust基础知识

函数中的语句和表达式

  • 函数体由一系列语句组成,可选的由一个表达式结束
  • Rust是一个基于表达式的语言
  • 语句是执行一些动作的指令
  • 表达式会计算产生一个值
  • 函数的定义也是语句
  • 语句不返回值,所以不可以使用let将一个语句赋值给一个变量
  • Rust基础知识

  • 字面值和字面值的计算都是表达式,表达式可以返回值
  • Rust基础知识

  • 注意函数的最后一行不能加;添加了;就表示为语句,语句不返回值,是一个空的元组,所以无法返回,不加;表达表达式,表达式可以返回值。
  • Rust基础知识

函数的返回值

  • 在 - >符号后面声明函数的返回值的类型,但是不可以为返回值命名
  • 在rust中,返回值就是函数体里面最后一个表达式的值
  • 若想提前返回,需使用return关键字,并指定一个值
    • 大多数函数都是默认使用最后一个表达式作为返回值
fn add(x:i32,y:i32) -> i32{
 x+y
}

当函数返回某个值时,请在函数参数列表后面和函数体的左大括号前面添加语法 -> <type>。箭头语法 -> 表示函数向调用方返回某个值。编译器通过 <type> 部分判断返回值的数据类型。

在 Rust 中,常见的做法是通过使函数中的最后一行代码等于要返回的值,从而在函数末尾返回一个值。以下示例显示此行为。 divide_by_5 函数将输入数除以 5 的结果返回到调用函数:

fn divide_by_5(num: u32) -> u32 {
    num / 5
}

fn main() {
    let num = 25;
    println!("{} divided by 5 = {}", num, divide_by_5(num));
}

运行结果如下:

Rust基础知识

使用return关键字

可以在函数中的任意位置使用 return 关键字来停止执行并将值发送回调用方。通常,return 关键字与条件测试结合使用。

在下面的示例中,如果 num 的值为 0,则显式使用 return 关键字提前从函数返回:

fn divide_by_5(num: u32) -> u32 {
    if num == 0 {
        // Return early
        return 0;
    }
    num / 5
}

Rust基础知识

显式使用 return 关键字时,语句以分号结束。如果在不使用 return 关键字的情况下发送回返回值,请勿以分号结束语句。你可能已注意到,我们没有将结束分号用于 num / 5 返回值语句。

提取函数消除重复的代码

原始代码,使用循环实现了找出list中最大的数

fn main(){
    let number_list = vec![34,50,100,65];
    let mut largest = number_list[0];
    for number in number_list{
        if number > largest{
            largest = number;
        }
    }
    println!("The largest number is {:?}", largest);
}

但是当有多个列表的时候,代码就会重复

fn main(){
    let number_list = vec![34,50,100,65];
    let mut largest = number_list[0];
    for number in number_list{
        if number > largest{
            largest = number;
        }
    }
    println!("number_list largest number is {:?}", largest);
    let number1_list = vec![100,34,600,89,54,2,43,8];
    let mut largest1 = number1_list[0];
    for number in number1_list{
        if number > largest1{
            largest1 = number;
        }
    }
    println!("number1_list largest number is {:?}", largest1);
}

重复代码的危害:

  • 容易出错
  • 需求变更时需要在多处进行修改 消除重复代码,提取公共部分定义函数
fn largest(list:&[i32])->i32{
    let mut largest = list[0];
    for &number in list{
        if number > largest{
            largest = number;
        }
    }
    largest
}
fn main(){
    let number_list = vec![34,50,100,65];
    println!("number_list largest number is {:?}", largest(&number_list));
    let number1_list = vec![100,34,600,89,54,2,43,8];
    println!("number1_list largest number is {:?}", largest(&number1_list));
}

rust中的方法

  • 方法和函数类似:fn 关键字、名称、参数、返回值
  • 方法与函数的不同之处:
    • 方法是在struct或(enum、trait对象)的上下文中定义
    • 方法的第一个参数是self,表示方法被调用的struct或(enum、trait对象)实例

定义方法

定义方法需要先有struct或(enum、trait对象)的声明,方法是和这些对象绑定在一起的,使用impl关键字进行声明方法,

  • 方法的第一个参数是self,即对象实例&self,也可以获取其所有权或可变借用,和其他参数一样
  • 方法的优点:可以更良好的组织代码
#[derive(Debug)]
struct Rectangle{
    width: u32,
    length: u32,
}
impl Rectangle{
 fn area(&self) -> u32{
  self.width * self.length
 }
}

方法的调用

方法的调用使用点标记法,实例.方法名即可

Rust基础知识

方法调用的运算符

  • 在C/C++中:Object->something()和(*object).something()一样
  • 在Rust中,没有->运算符
  • 但是Rust会自动引用或解引用
    • 在调用方法时就会发生这种行为
  • 在调用方法时,Rust会根据情况自动添加&、&mut、或*,以便object可以匹配方法的签名
  • 下面两行代码效果相同
    • P1.distance(&p2)
    • (&p1).distance(&p2)

方法的参数

方法同样可以拥有多个参数(除self外)

关联函数

可以在impl块里定义不把self作为第一个参数的函数,它们叫做关联函数(不是方法)

  • 例如:String::from
  • 关联函数通常用于构造器
  • 关联函数还可以用于模块创建的命名空间

创建关联函数

在impl块中定义关联函数

//定义长方形的struct

#[derive(Debug)]

struct Rectangle{

    width: u32,

    length: u32,

}

impl Rectangle {

    // 计算长方形的面积

    fn area(&self) -> u32{

        self.width * self.length

    }

    // 定义一个正方形

    fn square(size: u32) -> Rectangle{

        Rectangle { width: size, length: size }

    }

}

调用关联函数

使用实例::函数名进行调用

let s = Rectangle::square(10);

rust 中的注释

rust语言使用//做单行注释,多行注释使用/**

// 单行注释
/*
多行注释
*/

rust中还有一种文档注释,以后再说

rust中的变量

开发人员编写计算机程序来处理数据。收集、分析、存储、处理、共享和报告数据。我们使用变量将数据存储在命名引用中,稍后可在代码中引用这些数据。

声明变量

在 Rust 中,变量用关键字 let 声明。每个变量都有一个唯一的名称。声明变量后,可将其绑定到某个值,也可稍后在程序中绑定该值。以下代码声明名为 a_number 的变量。

let a_number;

a_number 变量尚未绑定到某个值。可修改此语句以将值绑定到变量:

let a_number = 10;

以下代码声明两个变量。声明第一个变量,但不绑定到某个值。声明第二个变量,并绑定到某个值。在后面的程序中,第一个变量的值绑定到某个字。代码调用 println! 宏来显示变量值。

fn main() {
    // 声明一个变量
    let a_number;
    // 声明第二个变量并绑定值
    let a_word = "Ten";
    // 将值绑定到第一个变量
    a_number = 10;
    println!("The number is {}.", a_number);
    println!("The word is {}.", a_word);
}

Rust基础知识

如果调用println! 宏并尝试在绑定 a_number 变量之前显示该变量的值,则编译器会返回错误,因为此时该变量还没有赋值

Rust基础知识

Rust基础知识

不变与可变

在Rust中,变量绑定默认不可变,如果变量不可变,在将值绑定到名称到,将无法改变此值。例如上面的代码,如果再次尝试修改a_number 的值,则会编译错误

Rust基础知识

如果要修改变量的值,则必须使用mut 关键字将变量绑定设为可变

let mut a_number;

Rust基础知识

添加mut 关键字后,已经可以修改变量的值了,所有不会报错,程序正常运行。

变量与常量

常量(constant),常量在绑定值以后也是不可变的,但是它与不可变的变量还是有很多的区别:

  • 常量不可以使用mut关键之,常量永远都是不可以变的
  • 声明常量使用const关键字,它的类型必须被标注
  • 常量可以在任何作用域内进行声明,包括全局作用域
  • 常量只可以绑定到常量表达式,无法绑定到函数的调用结果或只能运算时才能计算出的值 在程序运行期间,常量在其声明的作用域内一直有效 在rust中,常量的命名规范:常量使用全大写字母,每个单词之间用下划线分开在rust中,数字可以添加下划线增加可读性,不影响数字大小,如100_000

变量隐藏(shadowing)

可以声明与某个现有变量同名的新变量。新的声明会创建新的绑定。在 Rust 中,此操作称为“隐藏”,这是由于新变量会隐藏上一个变量。旧变量仍存在,但无法再于此范围内引用它。shadow和把变量标记为mut是不一样的:

  • 如果不使用let关键之,那么重新给非mut的变量赋值会导致编译时错误
  • 而使用let声明的同名新变量,也是不可变的
  • 使用let声明的同名新变量,它的类型可以与之前不同,但是使用let mut定义可变变量,类型不能改变
  • Rust基础知识

  • 以下代码演示隐藏的用法。声明名为 shadow_num 的变量。我们没有将变量定义为可变变量,因为每个 let 操作都会创建一个名为 shadow_num 的新变量,同时隐藏以前的变量绑定。
fn main() {
    // 声明第一个变量绑定,名称为 “shadow_num”
    let shadow_num = 5;
    // 声明第二个变量绑定,隐藏现有变量 “shadow_num”
    let shadow_num = shadow_num + 5;
    // 声明第三个变量绑定,隐藏变量 “shadow_num” 的第二个绑定
    let shadow_num = shadow_num * 2;
    println!("The number is {}.", shadow_num);
}

Rust基础知识

总结

  • Rust 程序的基本结构。 main 函数是所有 Rust 程序的入口点。 println! 宏可用于显示变量值和显示程序进度。可以使用 let 关键字定义变量。可以使用 mut 关键字将这些值声明为不可变或可变(可更改)。
  • Rust 语言概念,包括许多主要数据类型和复合数据类型。你学习了如何处理整数和浮点数、字符和文本字符串以及布尔 true/false 值。Rust 语言严格解释数据类型。只有在正确定义和使用了数据类型时,程序才能成功编译和运行。
  • 编写了一个函数,通过使用存储在 struct 和 enum 中的数据来生成汽车。在示例程序中查找了 todo! 宏的实例并完成了代码。使用了 Rust 操场来修改代码、编译程序并运行可执行文件。

了解详细信息

请访问以下链接,详细了解我们在本模块中探索的部分项目:

  • Rust 入门
  • 了解经典的 C 编程结构类型
  • 查看代数数据类型

Rust 参考文档

  • Rust 编程语言
  • 查看 Rust 关键字

Rust:数据类型

  • 使用数组
  • 使用布尔值
  • 使用字符
  • 使用十进制数和浮点类型
  • 使用枚举
  • 使用整数类型
  • 使用字符串
  • 使用结构
  • 使用元组

Rust:概念

  • 了解变量、可变性和隐藏
  • 了解函数
  • 使用 println! 显示输出 宏
  • 用 todo! 指示未完成的代码 宏
Rust基础知识

系列链接

1.  环境搭建

还有后续,学完慢慢发

Rust基础知识

end

Rust基础知识

扫码关注我哦

原文始发于微信公众号(宁雪):Rust基础知识

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月22日07:29:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Rust基础知识http://cn-sec.com/archives/2575513.html

发表评论

匿名网友 填写信息