Rust学习笔记_01——基础

embedded/2024/11/27 16:18:45/

文章目录

    • 1. Hello world
    • 2. 变量
      • 1. 变量声明
      • 2. 类型推断
      • 3. 变量绑定
      • 4. 重绑定(Shadowing)
    • 3. 值
    • 4. 算术
      • 4.1 基础运算
      • 4.2 整数 && 浮点数运算
      • 4.3 标准库函数
        • `std::cmp` 模块
        • `num_traits` 模块
      • 4.4 注意事项
    • 5. 类型推导
      • 5.1 工作原理
      • 5.2 限制
      • 5.3 类型注解的作用


1. Hello world

rust">fn main() {println!("hello world!")// 函数以 fn 开头。// 像 C 和 C++ 一样,块由花括号分隔。// main 函数是程序的入口点。// Rust 有卫生宏 (hygienic macros),println! 就是一个例子。// Rust 字符串是 UTF-8 编码的,可以包含任何 Unicode 字符。
}

在Rust中,宏是一种元编程工具,允许你在编译时生成代码。宏可以用来创建新的语法结构,简化重复的模式,或者实现其他语言特性。Rust的宏系统设计得非常强大且灵活,同时尽量保持安全性和可预测性。

卫生宏是Rust宏的一个重要特性,它确保了宏的使用不会意外地干扰到程序的其他部分。

println!() 是 Rust 中一个非常常用的宏,用于格式化字符串并将其打印到标准输出(通常是控制台)。这个宏是卫生宏的一个很好的例子,因为它展示了宏如何在不影响调用者代码的情况下安全地执行其功能。

println!() 宏的基本用法

rust">println!(fmt, arg1, arg2, ...);
  • fmt 是一个格式字符串,类似于 C 语言中的 printf
  • arg1, arg2, ... 是要插入到格式字符串中的参数。

格式字符串

格式字符串中可以包含占位符,这些占位符会被后面的参数替换。常见的占位符包括:

  • {}:自动选择合适的格式。
  • {:?}:调试格式(Debug trait)。
  • {:<width>}:左对齐,宽度为 width
  • {:>width}:右对齐,宽度为 width
  • {:^width}:居中对齐,宽度为 width
  • {:.precision}:设置浮点数的小数位数或字符串的最大长度。

卫生宏的特点

  1. 作用域隔离
    • println!() 宏内部定义的任何变量或标签都不会与调用者的作用域中的变量或标签冲突。例如,宏内部可能会使用临时变量来构建格式化的字符串,但这些变量不会泄漏到调用者的代码中。
  2. 防止捕获外部变量
    • println!() 宏只会捕获显式传递给它的参数。例如,如果你在格式字符串中使用了 {}, 那么你需要提供相应的参数。宏不会捕获调用者作用域中的其他变量,除非你明确地将它们传递给宏。
  3. 避免名称泄露
    • println!() 宏的内部实现细节对调用者是隐藏的。你不需要关心宏内部的具体实现,只需要知道如何使用它即可。

2. 变量

1. 变量声明

在Rust中,变量默认是不可变的(immutable),这意味着一旦赋值后就不能再修改。要声明一个不可变变量,使用 let 关键字:

rust">let x = 5; // 不可变变量

如果需要声明一个可变变量(mutable),可以在 let 关键字后面加上 mut 关键字:

rust">let mut y = 10; // 可变变量
y = 15; // 修改变量的值

2. 类型推断

Rust具有类型推断功能,编译器可以根据赋值表达式推断出变量的类型。不过,你也可以显式地指定类型:

rust">let z: i32 = 20; // 显式指定类型

3. 变量绑定

变量绑定是指将一个值绑定到一个变量名上。Rust中的变量绑定是不可变的,但可以通过 mut 关键字使其可变:

rust">let a = 1; // 不可变绑定
let mut b = 2; // 可变绑定
b = 3; // 修改可变变量的值

4. 重绑定(Shadowing)

Rust允许在同一作用域内重新声明一个变量,这称为重绑定(shadowing)。重绑定会创建一个新的变量,原来的变量仍然存在,但不可访问:

rust">let x = 5; // 第一次绑定
let x = x + 1; // 重绑定,创建一个新的变量 x
let x = x * 2; // 再次重绑定println!("The value of x is: {}", x); // 输出 "The value of x is: 12"

3. 值

  • 有符号整数
    • 类型:i8i16i32i64i128isize
    • 字面量:-1001_000123_i64
  • 无符号张数
    • 类型u8u16u32u64u128usize
    • 字面量:12310_u160
  • 浮点数
    • 类型:f32f64
    • 字面量:3.14-10.0e202_f32
  • Unicode标量类型
    • 类型:char
    • 字面量:'a'
  • 布尔值
    • 类型:bool
    • 字面量:truefalse

一些说明

  • iN, uNfN 占用 N 位,
  • isizeusize 占用一个指针大小的空间,
  • char 占用 32 位空间,
  • bool 占用 8 位空间。
  • 数字中的所有下划线均可忽略,它们只是为了方便辨识。因此,1_000 可以写为 1000(或 10_00),而 123_i64 可以写为 123i64

4. 算术

4.1 基础运算

  1. 加法 (+)

    rust">let a = 5;
    let b = 10;
    let sum = a + b; // sum 的值是 15
    
  2. 减法 (-)

    rust">let a = 10;
    let b = 5;
    let difference = a - b; // difference 的值是 5
    
  3. 乘法 (\*)

    rust">let a = 3;
    let b = 4;
    let product = a * b; // product 的值是 12
    
  4. 除法 (/)

    rust">let a = 20;
    let b = 4;
    let quotient = a / b; // quotient 的值是 5
    
  5. 取余 (%)

    rust">let a = 9;
    let b = 4;
    let remainder = a % b; // remainder 的值是 1
    

4.2 整数 && 浮点数运算

整数运算遵循上述基本运算符的规则。需要注意的是,整数除法会舍弃小数部分,例如:

rust">let a = 7;
let b = 3;
let quotient = a / b; // quotient 的值是 2,而不是 2.333...

浮点数运算同样遵循基本运算符的规则,但由于浮点数的表示精度问题,可能会出现一些细微的误差:

rust">let a = 7.0;
let b = 3.0;
let quotient = a / b; // quotient 的值是大约 2.3333333333333335

4.3 标准库函数

Rust标准库提供了一些额外的数学函数,主要位于 std::cmpnum_traits 等模块中。

std::cmp 模块

std::cmp 模块提供了比较函数,例如 maxmin,这些函数可以用于获取两个数值中的最大值或最小值:

rust">use std::cmp;let a = 10;
let b = 20;
let max_value = cmp::max(a, b); // max_value 的值是 20
let min_value = cmp::min(a, b); // min_value 的值是 10
num_traits 模块

num_traits 是一个外部库,提供了丰富的数值运算功能,包括求绝对值、幂运算、平方根等。要使用这个库,需要在 Cargo.toml 文件中添加依赖:

[dependencies]
num-traits = "0.2"

然后在代码中导入并使用相关函数:

rust">use num_traits::{Pow, Abs};let a = -5i32;
let b = 2;let power = a.pow(b); // power 的值是 25,因为 (-5)^2 = 25
let abs_value = a.abs(); // abs_value 的值是 5

4.4 注意事项

  1. 整数溢出:Rust的整数类型在运算时可能会发生溢出。为了避免溢出,可以使用 checked_add, checked_sub, checked_mul, 和 checked_div 等方法,这些方法在溢出时会返回 Option<T> 类型
  2. 浮点数精度:浮点数运算可能会受到精度限制,导致一些细微的误差。

5. 类型推导

Rust中的类型推导(Type Inference)是一种编译器功能,它允许程序员在编写代码时省略变量或表达式的类型注解,而编译器则会自动推断出这些类型。这种功能使得Rust代码更加简洁和易于编写,同时仍然保持了Rust的强类型系统所提供的类型安全性。

5.1 工作原理

Rust编译器通过以下几个步骤来推断类型:

  1. 局部类型推断:编译器首先会查看变量的初始值(如果有的话)来推断其类型。例如,如果有一个变量被初始化为一个整数字面量,那么编译器就会推断这个变量的类型为i32(在大多数情况下,整数字面量的默认类型)。
  2. 上下文依赖:编译器还会考虑变量在表达式中的使用上下文来推断类型。例如,如果一个变量被用作函数参数,并且该函数期望一个特定类型的参数,那么编译器就会推断该变量的类型为该函数参数所期望的类型。
  3. 泛型约束:当使用泛型时,编译器会根据泛型参数的使用方式和提供的类型约束来推断具体的类型。
  4. 类型统一:在推断过程中,编译器会尝试统一不同类型的表达式或变量,以确保它们在使用时具有兼容的类型。如果类型无法统一,编译器就会报错。

5.2 限制

  • 在某些情况下,编译器可能无法推断出变量的类型,这时就需要程序员显式地提供类型注解。
rust">let some_number; // 错误! 无法进行类型推导let some_number: i32; // OK
let some_number = 123; // OK
  • 当函数返回类型或泛型参数的类型无法从上下文推断出来时,也需要显式地提供类型注解

5.3 类型注解的作用

  1. 提高代码可读性:类型注解可以帮助其他程序员(或未来的你)更容易地理解代码。
  2. 避免潜在的错误:在某些复杂的表达式中,类型推导可能会失败或导致意外的结果。显式地提供类型注解可以避免这些错误。
  3. 与C/C++等语言的互操作性:当与C/C++等语言进行互操作时,可能需要显式地指定类型以确保正确的数据表示和传递。

http://www.ppmy.cn/embedded/140947.html

相关文章

UE5 Create Dynamic Material Instance(创建动态材质实例) 概述

在 Unreal Engine 5 (UE5) 中&#xff0c;Create Dynamic Material Instance 节点用于创建材质的动态实例。动态材质实例是基于某个已有的材质或材质实例的副本&#xff0c;并允许在运行时修改其属性&#xff08;例如颜色、纹理、参数等&#xff09;。这个节点在游戏开发中非常…

TCP/IP 协议:网络世界的基石(2/10)

一、引言 在当今数字化时代&#xff0c;互联网已经成为人们生活中不可或缺的一部分。而在互联网的背后&#xff0c;TCP/IP 协议扮演着至关重要的角色&#xff0c;堪称互联网的基石。 TCP/IP 协议是一组用于数据通信的协议集合&#xff0c;它的名字来源于其中最重要的两个协议…

深度学习-47-大语言模型LLM之常用的大模型微调框架选择建议

文章目录 1 微调框架1.1 LLaMA-Factory1.1.1 模块化设计(简化微调与推理流程)1.1.2 多硬件支持(适应不同环境需求)1.1.3 量化技术(降低内存占用提升推理速度)1.2 Unsloth1.2.1 加速微调(大幅提升微调速度)1.2.2 降低内存使用(突破资源限制)1.2.3 广泛的模型支持(兼容多种主流LL…

文件的处理(c语言)

首先了解下文件的作用 文件可以把数据直接放在电脑的硬盘上&#xff0c;实现了数据的持久化 什么是文件 文件就是磁盘上的文件。在程序设计中&#xff0c;文件通常有俩种&#xff0c;一种是程序文件&#xff0c;另一种是数据文件&#xff08;这是从文件功能来分类的&#xff…

如何寻找适合的HTTP代理IP资源?

一、怎么找代理IP资源&#xff1f; 在选择代理IP资源的时候&#xff0c;很多小伙伴往往将可用率作为首要的参考指标。事实上&#xff0c;市面上的住宅IP或拨号VPS代理IP资源&#xff0c;其可用率普遍在95%以上&#xff0c;因此IP可用率并不是唯一的评判标准 其实更应该关注的…

C++设计模式之组合模式中适用缓存机制提高遍历与查找速度

在组合设计模式中&#xff0c;为了提高反复遍历和查找的速度&#xff0c;可以引入缓存机制。缓存机制可以通过存储已经遍历过的子组件或计算过的结果来减少重复操作的开销。以下是一个示例&#xff0c;展示了如何在组合模式中使用缓存机制来提高性能。 示例&#xff1a;组合设…

【微服务】 Eureka和Ribbon

一、Eureka 服务调用出现的问题&#xff1a;在远程调用另一个服务时&#xff0c;我们采用的解决办法是发送一次http请求&#xff0c;每次环境的变更会产生新的地址&#xff0c;所以采用硬编码会出现很多麻烦&#xff0c;并且为了应对并发问题&#xff0c;采用分布式部署&#…

Hive-定时清理无用的临时表

背景&#xff1a; 有一个临时库&#xff0c;大家平时开发过程中比较常用&#xff0c;这个库的表的生命周期没有得到很好的管理&#xff0c;日积月累导致无用表增多&#xff0c;所以跟运维提了个方案&#xff0c;定期清理。提出了一个比较简单的方案。 解决方案&#xff1a; sh…