【Rust】001-基础语法:变量声明及数据类型

news2024/11/25 11:33:43

【Rust】001-基础语法:变量声明及数据类型

文章目录

  • 【Rust】001-基础语法:变量声明及数据类型
  • 一、概述
    • 1、学习起源
    • 2、依托课程
  • 二、入门程序
    • 1、Hello World
    • 2、交互程序
      • 代码演示
      • 执行结果
    • 3、继续上难度:访问链接并打印响应
      • 依赖
      • 代码
      • 执行命令
  • 三、数据类型
    • 1、标量类型
      • 整型标量类型
      • 其它
    • 2、复合类型
  • 四、变量声明与使用
    • 1、常量
      • 代码演示
      • 执行结果
    • 2、变量
      • 代码演示
      • 执行结果
    • 3、变量名复用
      • 代码演示
      • 执行结果
    • 4、声明时指定变量类型
      • 代码演示
      • 执行结果
    • 5、元组的使用
      • 代码演示
      • 执行结果
    • 6、数组的使用
      • 代码演示
      • 执行结果
    • 7、字符串
      • 代码演示
      • 执行结果
  • 五、演示 `Ownership(所有权)`、`Borrowing(借用)` 和 `Lifetime(生命周期)` 的基本概念的示例
      • 代码演示
      • 执行结果
  • 六、const 和 let 的区别
      • 1. 可变性(Mutability)
      • 2. 类型注解
      • 3. 初始化表达式
      • 4. 作用域和生命周期
      • 5. 内联

一、概述

1、学习起源

“一切能用 Rust 重写的项目都将或者正在用 Rust 重写”

2、依托课程

Rust 入门与实践:https://juejin.cn/book/7269676791348854839?utm_source=course_list

二、入门程序

1、Hello World

fn main() {
    // 打印字符串
    println!("Hello, world!");
}

2、交互程序

代码演示

use std::io; // 使用标准库中的 io 这个模块

fn main() {
    // 打印字符串
    println!("Hello, world!");
    // 打印字符串
    println!("请输入一个数字: ");
    // 在这里我们创建了一个新的 String,用来接收下面的输入
    let mut input = String::new();
    io::stdin()
        .read_line(&mut input) // 读取一行
        .expect("Failed to read input!"); // 比较粗暴的错误处理
    // 打印输入的原始内容
    println!("Your raw input is: {:?}.", input);
    // trim 把前后的空格、换行符这些空白字符都去掉,parse 将输入的字符串解析为 i64 类型,如果解析失败就报错
    let number: i64 = input.trim().parse().expect("Input is not a number!");
    // 打印 parse 之后的 i64 数字
    println!("Your input is: {}.", number);
}

执行结果

C:/Users/Administrator/.cargo/bin/cargo.exe run --color=always --package hello_rust --bin hello_rust
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target\debug\hello_rust.exe`
Hello, world!
请输入一个数字: 
100
Your raw input is: "100\n".
Your input is: 100.

进程已结束,退出代码为 0

3、继续上难度:访问链接并打印响应

依赖

Cargo.toxml

[package]
name = "hello_rust"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = { version = "4", features = ["derive"] }
reqwest = { version = "0.11", features = ["blocking"] }

代码

// 使用 use 引入一个标准库的包,或者第三方的包
use std::error::Error;

// clap 是一个 Rust 社区开发的命令行参数解析库
use clap::Parser;

// reqwest 是一个 Rust 社区开发的 HTTP 客户端库
use reqwest::blocking::Client;
use reqwest::header::HeaderMap;

// 使用 derive 宏,用于自动生成 Parser 的实现
// 在高级特性章节中我们会学到宏的用法及原理
#[derive(Parser)]
#[command(
author,
version,
about = "Sends HTTP requests and prints detailed information"
)]
struct Cli {
    // arg 宏用于标记命令行参数,这里标记了一个必须的 URL 参数
    #[arg(short, long, help = "Target URL", required = true)]
    url: String,
}

/// Rust 程序入口
fn main() -> Result<(), Box<dyn Error>> {
    // 解析命令行参数
    let cli = Cli::parse();

    // 发起 HTTP 请求
    // ? 是 Rust 中的错误传播语法糖,我们会在接下来的章节中学习
    let response = send_request(&cli.url)?;

    // 打印 HTTP 响应的详细信息
    print_response_details(response)?;

    Ok(())
}

/// 发起一个 HTTP 请求
/// 参数是目标 URL 的引用
/// 返回值是一个 Result,如果请求成功返回 Response,否则返回一个动态 Error
fn send_request(url: &str) -> Result<reqwest::blocking::Response, Box<dyn Error>> {
    // 创建一个 HTTP 客户端
    let client = Client::builder().build()?;

    // 使用 GET 方法发起请求
    let response = client.get(url).send()?;

    Ok(response)
}

/// 打印出 HTTP 响应的详细信息
/// 参数是 Response 对象
/// 返回值是一个 Result,用于错误处理
fn print_response_details(response: reqwest::blocking::Response) -> Result<(), Box<dyn Error>> {
    // 打印 HTTP 状态码
    println!("Status: {}", response.status());

    // 打印 HTTP 响应头
    println!("Headers:");
    print_headers(response.headers());

    // 读取并打印 HTTP 响应体
    let body = response.text()?;
    println!("Body:\n{}", body);

    Ok(())
}

/// 打印出 HTTP 响应头
/// 参数是 HeaderMap 的引用
fn print_headers(headers: &HeaderMap) {
    for (key, value) in headers.iter() {
        // 打印每个响应头的键和值
        // 如果值不是 UTF-8 字符串,就打印 [unprintable]
        println!(" {}: {}", key, value.to_str().unwrap_or("[unprintable]"));
    }
}

执行命令

根目录执行

cargo run -- --url https://juejin.cn/

三、数据类型

1、标量类型

整型标量类型

image-20230902162358238

只要记得最低从 8 开始,到 128 结束(当然,正常情况下我们最多用到 64,128 在很多平台上需要软件模拟而不是硬件支持,不推荐大家用);在赋值的时候除了直接十进制数字赋值外,还支持以下语法(大家了解一下就好,不用死记硬背):

image-20230902162458543

其它

  • 浮点数:f32 / f64
  • bool
  • char:这个比较特殊,Rust 中一个 char 占 4 字节,存放的是一个 UTF-32,而不像 C/C++ 那样本质上是个 u8

2、复合类型

  • 元组 tuple:let a = (1, 2); let (a, b) = (1, 2)
  • 数组 array: let a = [1, 2, 3]; let a = [0; 5] // 这个声明中 0 是默认值,5 是长度,等价于 let a = [0, 0, 0, 0, 0]

四、变量声明与使用

1、常量

代码演示

fn main() {
    // 声明常量,表示年龄
    const AGE: u32 = 18;
    // 声明常量,表示名字
    let name = "张三";
    // 打印名字和年龄
    println!("{}的年龄是{}", name, AGE);
}

执行结果

张三的年龄是18

2、变量

代码演示

fn main() {
    // 声明变量,表示年龄
    let mut age = 18;
    // 打印变量
    println!("age = {}", age);
    // 修改变量
    age = 20;
    // 打印变量
    println!("age = {}", age);
}

执行结果

age = 18
age = 20

3、变量名复用

代码演示

fn main() {
    // 声明常量,表示年龄
    let age = 18;
    // 打印年龄
    println!("age = {}", age);
    // 再次声明 age 变量,此时不会报错
    let age = 20;
    // 打印年龄
    println!("age = {}", age);
}

执行结果

age = 18
age = 20

4、声明时指定变量类型

代码演示

fn main() {
    // 声明常量,表示年龄
    let age: i32 = 18;
    // 打印年龄
    println!("age = {}", age);
}

执行结果

age = 18
age = 20

5、元组的使用

代码演示

fn main() {
    // 声明一个包含三个元素的元组
    let my_tuple = (1, "hello", 3.14);

    // 使用索引访问元组中的元素
    println!("第一个元素是:{}", my_tuple.0); // 输出 "第一个元素是:1"
    println!("第二个元素是:{}", my_tuple.1); // 输出 "第二个元素是:hello"
    println!("第三个元素是:{}", my_tuple.2); // 输出 "第三个元素是:3.14"

    // 使用模式匹配解构元组
    let (x, y, z) = my_tuple;
    println!("解构后 x 的值是:{}", x); // 输出 "解构后 x 的值是:1"
    println!("解构后 y 的值是:{}", y); // 输出 "解构后 y 的值是:hello"
    println!("解构后 z 的值是:{}", z); // 输出 "解构后 z 的值是:3.14"

    // 忽略元组中不需要的值
    let (a, _, _) = my_tuple;
    println!("只需要第一个元素:{}", a); // 输出 "只需要第一个元素:1"

    // 嵌套元组
    let nested_tuple = (1, (2, 3), 4);
    let (_, (b, c), _) = nested_tuple;
    println!("嵌套元组中 b 的值和 c 的值分别是:{} 和 {}", b, c); // 输出 "嵌套元组中 b 的值和 c 的值分别是:2 和 3"
}

执行结果

第一个元素是:1
第二个元素是:hello
第三个元素是:3.14
解构后 x 的值是:1
解构后 y 的值是:hello
解构后 z 的值是:3.14
只需要第一个元素:1
嵌套元组中 b 的值和 c 的值分别是:2 和 3

6、数组的使用

代码演示

fn main() {
    // 声明一个包含5个元素的整数数组
    let int_array = [1, 2, 3, 4, 5];

    // 声明一个包含5个元素的浮点数数组,同时指定类型
    let float_array: [f64; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];

    // 使用索引访问数组中的元素
    println!("整数数组的第一个元素是:{}", int_array[0]);  // 输出 "整数数组的第一个元素是:1"
    println!("浮点数数组的第二个元素是:{}", float_array[1]);  // 输出 "浮点数数组的第二个元素是:2.0"

    // 使用循环遍历整数数组
    println!("整数数组的所有元素:");
    for num in int_array.iter() {
        print!("{} ", num);  // 输出 "1 2 3 4 5 "
    }
    println!();

    // 使用循环遍历浮点数数组,并获取索引
    println!("浮点数数组的所有元素和对应的索引:");
    for (index, num) in float_array.iter().enumerate() {
        println!("索引:{}, 元素:{}", index, num);
        // 输出 "索引:0, 元素:1.0"
        // 输出 "索引:1, 元素:2.0"
        // ...
    }

    // 声明一个全部元素为0的数组
    let zero_array: [i32; 5] = [0; 5];
    println!("全为0的数组:{:?}", zero_array);  // 输出 "全为0的数组:[0, 0, 0, 0, 0]"
}

执行结果

整数数组的第一个元素是:1
浮点数数组的第二个元素是:2
整数数组的所有元素:
1 2 3 4 5 
浮点数数组的所有元素和对应的索引:
索引:0, 元素:1
索引:1, 元素:2
索引:2, 元素:3
索引:3, 元素:4
索引:4, 元素:5
全为0的数组:[0, 0, 0, 0, 0]

7、字符串

代码演示

fn main() {
    // 使用字符串字面量声明一个不可变字符串
    let hello_str = "Hello, world!";
    println!("不可变字符串字面量:{}", hello_str);  // 输出 "不可变字符串字面量:Hello, world!"

    // 使用 String::from 创建一个可变字符串
    let mut hello_string = String::from("Hello");
    println!("可变字符串:{}", hello_string);  // 输出 "可变字符串:Hello"

    // 在可变字符串后追加字符串
    hello_string.push_str(", world!");
    println!("追加后的可变字符串:{}", hello_string);  // 输出 "追加后的可变字符串:Hello, world!"

    // 字符串拼接
    let concat_str = [hello_str, " ", &hello_string].concat();
    println!("拼接后的字符串:{}", concat_str);  // 输出 "拼接后的字符串:Hello, world! Hello, world!"

    // 使用索引获取字符串中的字符(注意:这种方式不推荐,因为会导致错误或崩溃)
    // let first_char = hello_str[0];  // 这样是错误的
    // Rust 的字符串是 UTF-8 编码的,直接索引可能会导致字符被截断。

    // 使用 chars 方法遍历字符串中的字符
    println!("使用 chars 方法遍历字符串:");
    for ch in hello_str.chars() {
        print!("{} ", ch);  // 输出 "H e l l o ,   w o r l d ! "
    }
    println!();

    // 使用 bytes 方法遍历字符串中的字节
    println!("使用 bytes 方法遍历字符串字节:");
    for byte in hello_str.bytes() {
        print!("{} ", byte);  // 输出对应的 ASCII 或 UTF-8 编码的字节值
    }
    println!();

    // 获取字符串长度
    println!("字符串 '{}' 的长度是:{}", hello_str, hello_str.len());  // 输出 "字符串 'Hello, world!' 的长度是:13"
}

执行结果

不可变字符串字面量:Hello, world!
可变字符串:Hello
追加后的可变字符串:Hello, world!
拼接后的字符串:Hello, world! Hello, world!
使用 chars 方法遍历字符串:
H e l l o ,   w o r l d ! 
使用 bytes 方法遍历字符串字节:
72 101 108 108 111 44 32 119 111 114 108 100 33 
字符串 'Hello, world!' 的长度是:13

五、演示 Ownership(所有权)Borrowing(借用)Lifetime(生命周期) 的基本概念的示例

代码演示

// 定义一个函数,演示所有权的转移
fn takes_ownership(some_string: String) {
    println!("函数内部:{}", some_string);
}  // 这里 some_string 离开作用域,所有权也随之释放

// 定义一个函数,演示借用(不可变)
fn borrows_immutable(s: &String) {
    println!("函数内部(不可变借用):{}", s);
}

// 定义一个函数,演示借用(可变)
fn borrows_mutable(s: &mut String) {
    s.push_str(", world!");  // 修改字符串
    println!("函数内部(可变借用):{}", s);
}

// 定义一个函数,演示生命周期
// 注:'a 是生命周期标注,表明 x 和 y 的生命周期相同,并且与返回值的生命周期也相同
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    // 所有权(Ownership)
    let s1 = String::from("hello");  // s1 获取了字符串 "hello" 的所有权
    takes_ownership(s1);  // 所有权转移到函数 takes_ownership
    // println!("main 函数:{}", s1);  // 错误!因为 s1 的所有权已经被转移

    // 借用(Borrowing)
    let s2 = String::from("hello");  // s2 获取了字符串 "hello" 的所有权
    borrows_immutable(&s2);  // 不可变借用,所有权仍在 s2
    println!("main 函数(不可变借用后):{}", s2);

    let mut s3 = String::from("hello");  // s3 获取了字符串 "hello" 的所有权,并且是可变的
    borrows_mutable(&mut s3);  // 可变借用,所有权仍在 s3,但内容已经被修改
    println!("main 函数(可变借用后):{}", s3);

    // 生命周期(Lifetime)
    let str1 = "Rust";
    let str2 = "Programming";
    let result = longest(str1, str2);
    println!("更长的字符串是:{}", result);  // 输出 "更长的字符串是:Programming"
}

执行结果

函数内部:hello
函数内部(不可变借用):hello
main 函数(不可变借用后):hello
函数内部(可变借用):hello, world!
main 函数(可变借用后):hello, world!
更长的字符串是:Programming

六、const 和 let 的区别

1. 可变性(Mutability)

  • let: 默认情况下,使用 let 声明的变量是不可变的,但您可以使用 mut 关键字来使其可变。

    let x = 5;  // 不可变
    let mut y = 6;  // 可变
    
  • const: 使用 const 声明的常量始终是不可变的,并且不能使用 mut

    const X: i32 = 5;  // 始终不可变
    

2. 类型注解

  • let: 可以选择是否添加类型注解。

    let x = 5;  // 类型推断为 i32
    let y: i64 = 6;  // 显示类型注解
    
  • const: 必须添加类型注解。

    const X: i32 = 5;  // 必须提供类型
    

3. 初始化表达式

  • let: 可以使用任何类型的表达式进行初始化。

    let x = 5 + 5;  // 算术表达式
    
  • const: 只能使用常量表达式进行初始化。

    const X: i32 = 5 + 5;  // 常量表达式,但不能是函数调用、运行时计算等
    

4. 作用域和生命周期

  • let: 局部变量,作用范围仅限于声明它的代码块。
  • const: 可以在模块级别使用,生命周期可跨越整个程序。

5. 内联

  • const: 在编译时,常量的值会被直接内联到使用它的表达式中。
  • let: 取决于编译器优化。

总体来说,const 主要用于那些在编译时就能确定并且永远不会改变的值,而 let 则用于运行时可能会改变的值。希望这能帮助您更好地理解这两者之间的区别!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/964681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mac帧 arp

1.分片 2.MSS max segment size 3.跨网络的本质 就是经历很多的子网或者局域网 4.将数据从A主机跨网络送到B主机的能力 IP和mac IP解决的是路径选择的问题 5.数据链路层 用于两个设备&#xff08;同一种数据链路节点&#xff09;之间进行传递 6.以太网ether 7.局域网通…

Django传递dataframe对象到前端网页

在django前端页面上展示的数据&#xff0c;还是使用django模板自带的语法 方式1 不推荐使用 直接使用 【df.to_html(indexFalse)】 使用to_html他会生成一个最基本的表格没有任何的样式&#xff0c;一点都不好看&#xff0c;如果有需要的话可以自行修改表格的样式&#xff0c;…

QEMU 啓動gdb 調試

背景 上一章介紹了如何使用QEMU 運行RISC-V 程序, GDB 作爲強大的代碼調試工具,對軟件開發至關重要,本章介紹如何啓動GDB 調試 CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132522853 開啓GDB 服務 QEMU 啓動時添加-s參數, 代碼啓用本地GDB 服務, 默認端口號爲1234.…

Numpy数组(随时更新)

一、Numpy数组对象的重要属性 #导入库 import numpy as npdata np.arange(12).reshape(4,3)data2 np.arange(24).reshape(3,4,2) #ndim维度个数data.ndimdata2.ndim #shape形状几行几列 数组的维度data.shapedata2.shape#size数组的总个数data.sizedata2.size #dtype数组元素的…

《爵士乐史》乔德.泰亚 笔记

第一章 【美国音乐的非洲化】 【乡村布鲁斯和经典布鲁斯】 布鲁斯&#xff1a;不止包括忧愁、哀痛 十二小节布鲁斯特征&#xff1a; 1.乐型&#xff08;A:主、B:属、C/D:下属&#xff09;&#xff1a;A→A→B→A→C→D→A→A 2.旋律&#xff1a;大三、小三、降七、降五 盲人…

2023河南萌新联赛第(八)场 南阳理工学院F小前前

思路&#xff1a; 每次查询L - R的 最大连续子区间的或值 但是 我们都知道或的话 只会增加 不会减少 所以 L - R 的或值就是最大的子区间 然后再求与x的或值就ok了 但是 n1e5 q1e5 我们不能每次循环都暴力跑一边 那肯定是不行的 这里我们可以把他们拆成2进制 存放到二维数组里…

项目一:基于YOLOv7的输电线路销钉缺失检测项目

1. YOLOv7模型介绍 YOLOv7是目标检测算法YOLO&#xff08;You Only Look Once&#xff09;的第七个版本&#xff0c;也是目前较流行的YOLO算法版本之一。 YOLOv8主要结构&#xff1a; 1. Backbone网络&#xff1a;采用CSPDarknet53作为主干网络&#xff0c;在不增加参数数量…

springboot之一:配置文件(内外部配置优先顺序+properties、xml、yaml基础语法+profile动态切换配置、激活方式)

配置的概念&#xff1a; Spring Boot是基于约定的&#xff0c;所以很多配置都有默认值&#xff0c;但如果想使用自己的配置替换默认配置的话&#xff0c;就可以使用application.properties或者application.yml(application.yaml)进行配置。 注意配置文件的命名必须是applicat…

详解MES中的四大现场执行管理模式

导 读 ( 文/ 3426 ) 制造业是全球经济中至关重要的一部分&#xff0c;随着市场竞争的加剧和客户需求的多样化&#xff0c;企业需要寻找合适的生产方式来提高生产效率、降低成本并保证产品质量。在这个背景下&#xff0c;制造执行系统&#xff08;MES&#xff09;作为连接管理层…

【LLM模型篇】LLaMA2 | Vicuna | EcomGPT等(更新中)

文章目录 一、Base modelchatglm2模型Vicuna模型LLaMA2模型1. 训练细节2. Evaluation Results3. 更多参考 alpaca模型其他大模型和peft高效参数微调二、垂直领域大模型MedicalGPT&#xff1a;医疗大模型TransGPT&#xff1a;交通大模型​EcomGPT&#xff1a;电商领域大模型1. s…

WPF Material Design 初次使用

文章目录 前言相关资源快速开始快速开始说明地址 吐槽一下 前言 MD全称MaterialDesignInXamlToolkit&#xff0c;MaterialDesign和Bootstrap一样&#xff0c;都是一个UI风格库。相当于衣服中的休闲服&#xff0c;汉服&#xff0c;牛仔裤一样&#xff0c;就是风格不一样的Ui框架…

【包过滤防火墙-iptables】的简单使用

文章目录 规则链的分类--五链处理的动作iptables常用参数和作用 防火墙就是堵和通的作用 iptables &#xff1a;包过滤防火墙&#xff0c;是内核防火墙netfilter的管理工具 核心&#xff1a;四表五链 规则链的分类–五链 在进行路由选择前处理的数据包&#xff1a;PREROUTIN…

财报解读:成功通过“期中考”,创维多元布局产生多大协同效应?

2023年以来&#xff0c;在下游市场需求仍在复苏以及存量市场竞争加剧的背景之下&#xff0c;消费电子行业的发展受到不小挑战。不过&#xff0c;从中期业绩来看&#xff0c;可以发现一些企业还是具备一定的风险抵御能力&#xff0c;发展韧性显著&#xff0c;创维就是其中一员。…

十大管理——项目成本管理

目录 1.成本管理概念 2.成本管理的四个过程域 2.1四个过程的整体理解 ​2.2四个过程的ITO口诀版记忆 2.3过程1——制定项目管理计划 ​2.4过程2——项目成本估算​ 2.5过程3——项目成本预算 2.5过程4——项目成本控制 3计算题 1.成本管理概念 项目成本管理就是要确保…

window 常用基础命令

0、起步 0-1) 获取命令的参数指引 netstat /? 0-2) 关于两个斜杠&#xff1a; window 文件路径中使用反斜杠&#xff1a;\ linux 文件路径中使用&#xff1a;/ 1、开关机类指令 shutdown /s # 关机shutdown /r # 重启shutdown /l …

设备数据采集的挑战与机遇

导 读 ( 文/ 1661 ) 在现代制造业中&#xff0c;数据是实现高效、质量和盈利的关键驱动力。工厂设备数据采集是一种通过收集、分析和利用设备和流程数据&#xff0c;以提高生产效率、质量和可靠性的方法。 工厂设备数据可以提供有关设备性能、效率、健康状况和生产状况的…

OS 段页结合的实际内存管理

虚拟内存承接段和页&#xff0c;从用户角度&#xff0c;虚拟内存提供段&#xff0c;从硬件角度&#xff0c;虚拟内存把段打散映射到页 先基于段的翻译&#xff0c;再基于页的翻译 p是pcb跟着进程换&#xff0c;64M一个段&#xff0c;set base就是建段表 因为每个进程虚拟地址…

Java智慧工地源码 智慧工地APP源码

Java智慧工地源码 智慧工地APP源码 系统定义&#xff1a; 智慧工地信息化管理平台是依托计算机信息、网络通讯、物联网、系统集成及云计算技术&#xff0c;通过数据采集、信息动态交互、智能分析&#xff0c;建立起来的一套集成的项目建设综合管理系统。实现项目管理信息化、网…

51单片机项目(8)——基于51单片机的DS1302时钟系统

本次做的设计&#xff0c;是利用DS1302时钟芯片&#xff0c;做了一个时钟&#xff0c;并且将实时时间通过串口发送到上位机进行显示。系统运行如下&#xff1a;&#xff08;protues文件和相关keil代码会在文章最后给出&#xff01;&#xff01;&#xff01;&#xff09; DS1302…