首页 > 其他分享 >Rust 变量和基础类型

Rust 变量和基础类型

时间:2024-10-11 15:00:09浏览次数:1  
标签:变量 .. 切片 let 数组 类型 Rust

通过 let 关键字声明变量, 变量默认是不可变 (只读) 的.

let foo = 5; // 创建了一个不可变的变量 foo, 并绑定了 5
foo = 10; // 不能对 foo 重新绑定

// 使用 mut 关键字创建可变的
let mut bar = 5;
bar = 10; // 可以重新绑定

不需要写变量类型, 编译器可以自己推导, 但是常量 (const) 和静态变量 (static) 必须声明类型.

也可以使用相同的名字声明新的变量, 新的变量就会隐藏之前的声明的同名变量.

let x = 1;
// 第二次声明的 x 可以和第一次声明的 x 类型不一样.
let x = "";

常量

使用 const 关键字声明常量.

它和变量的区别:

  • 不能使用 mut 关键字, 常量必须是不可变的.

  • 常量必须指定类型.

  • 常量可以在任何作用域内进行声明, 包括全局作用域.

  • 常量只可以绑定到常量表达式, 无法绑定到函数的调用结果或只能在运行时才能计算出的值.

    比如: 10*10 就是常量表达式, 10*i 就是通过运行时才能计算.

    但是有另外一种情况, 如果 i 也是常量, 那么就没问题.

const MAX_POINTS: u32 = 100_000; // 使用下划线是为了提高可读性.
// 在代码中使用了 MAX_POINTS 常量, 在编译的时候会直接替换为实际值 100_000.

静态变量

静态变量的语法和常量的语法相似, 只不过静态变量可以使用 mut 关键字.

static HELLO: &str = "Hello, world!";

静态变量的生命周期和整个程序的生命周期一样.

数据类型

栈上保存的是固定大小类型的值, 比如指针, u8, char 类型等, 这些类型都是固定大小的.

堆上保存的是非固定大小类型的值, 这些值在使用的时候会动态调整大小.

Rust 不支持隐式类型转换, 比如不会自动将 16 位整数转换为 32 位整数.

数字类型

分组 说明
i8, i16, i32, i64, i128 有符号整数类型, 范围是 8 位到 64 位.
u8, u16, u32, u64, u128 无符号整数类型, 范围是 8 位到 64 位.
f32, f64 浮点数类型, 有 32 位和 64 位两种.
isize, usize 在 64 位 CPU 上, isize 和 usize 都是 64 位.

虽然都是数字类型, 但是不同的数字类型不能比较.

比如 i16 > u16 不能比较, i16 > i32 也不能比较, 但是可以通过 std::convert::TryFrom 进行转换.

元组 (Tuple)

元组的长度是固定的, 一旦声明就无法改变, 但是每一个元素都可以是不同的类型.

let tup:(i32, f64, u8) = (500, 6.4, 1);

// 不能使用 tup[0], 也不能使用变量 tup.(1-1).
println!("{}, {}, {}", tup.0, tup.1, tup.2);

// 第二种使用方式, 叫做元组的析构.
let (x, y, z) = tup;
println!("{}, {}, {}", x, y, z);

() 是什么意思

  • 单元类型: 类似于其它编程语言中的 void.

  • 占位符: 在使用 Result<T, E> 类型时, 如果你只关心错误情况, 而成功情况不返回任何有意义的值, 你可以使用 () 作为 Ok 类型的值.

  • 空元组

数组

数组长度也是固定的, 一旦声明就无法改变, 而且每一个元素的类型必须相同.

数组的大小也是类型的一部分, 比如 [i32; 5][i32; 6] 是两个类型.

// 创建了一个长度为 5, 类型为 i32 的数组.
let a = [1, 2, 3, 4, 5];

// 创建了一个长度为 5, 类型为 i32 的数组,
// 但是数组中的元素都是 3.
let a = [3; 5];

// 这是错误的, 数组长度不能是变量.
// let a = [3; i];

切片

[T] 它就是一个切片类型, 表示一个动态大小的视图.

它只是对数据进行引用, 并不会复制数据或拥有数据的所有权.

动态大小是什么意思?

先来说一下静态大小, 比如说数组就是一个静态大小的, 因为数组在创建的时候就需要指定数组的大小.

然后动态大小就是反过来的, 就是说在创建的时候不需要指定大小, 而是在运行的时候才去确定大小.

不能直接使用切片类型, 因为编译器在编译的时候, 必须知道类型的大小.

你可能会想 t[0..3] 是用来创建切片的, 那么不是已经知道了切片的长度吗?

对, 确实可以在编译时推断出切片的长度, 但是编译器在处理切片的时候, 还是按照动态大小类型处理的.

let t = [3; 10];
// let t1: [i32] = t[0..3]; // 不能直接使用切片

// t[0..3] 创建切片, 然后获取这个切片的不可变引用.
let t1: &[i32] = &t[0..3];

下面是切片的使用:

let array = [1, 2, 3, 4, 5];

// 通过现有的数组创建出来一个切片,
// &[开始索引..结束索引],包头不包尾.
// &[开始索引..=结束索引],包头包尾.
//
// 还有一些简化方式:
// &[..结束索引]
// &[开始索引..]
// &[..]
&array[1..4]

可以对一个切片, 再进行切片.

下图比较清晰地呈现了切片和数据之间的关系:

下图比较清晰地呈现了切片和数据之间的关系.jpg

切片可以是可变的, 也可以是不可变的, 而且还可以通过 Box<[T]>, 在堆上分配切片.

切片文档: https://doc.rust-lang.org/std/primitive.slice.html

下图描述了数组、Vec<T>、切片引用 &[T]&mut [T], 以及在堆上分配的切片 Box<[T]> 之间的关系.

切片数组相互转换.jpg

Vec

Vector 是数组实现的, 适用于随机访问和频繁在尾部插入元素.

创建 Vector:

let my_vector: Vec<i32> = Vec::new();

// 类型 i32.
let my_vector = vec![1, 2, 3];

// 保存 u8 类型, 长度是 10, 默认值是 0.
let my_vector = vec![0u8; 10];

Vector 中的所有元素都是保存在堆内存中的, 比如上面的元素 1, 2, 3 也是保存在堆内存中的.

还有两个常用类型:

  • VecDeque: 是一个双端队列, 适用于在两端频繁添加和移除元素.

  • LinkedList: 是一个双向链表, 适用于在任意位置频繁插入和删除元素, 但不需要高效随机访问的场景.

HashMap

键值对的形式存储数据, 一个键 (Key) 对应一个值 (Value).

use std::collections::HashMap;

let mut my_hashmap: HashMap<String, i32> = HashMap::new();

HashMap 中的所有元素都是保存在堆内存中的.

还有两个常用类型:
  • BTreeMap: 通过 B 树数据结构实现的有序键值对集合.
  • BTreeSet: 和 BTreeMap 类似, 只不过它的 key 不能重复.

如何解决冲突?

使用开放寻址法的二次探查来解决.

Rust-二次探查.jpg

要向 HashMap 中插入 e:5 数据, 通过 key: e 计算出来的 Hash 值, 是要将数据放在数组的 03 下标中.

但是 03 下标已经有数据了, 所以通过公式 hash(key)+N^2 计算下一个下标.

上面公式中的 N 是步长, 下标 03 中存放数据, 通过步长 1 找到下一个下标 04, 它也有数据所以步长加 1, 然后找到 07 下标.

标签:变量,..,切片,let,数组,类型,Rust
From: https://www.cnblogs.com/zy24/p/18458155

相关文章

  • centos7 安装Python3及配置环境变量
    centos7安装Python3并配置环境变量亲测有效python官网(linux下载地址、版本可自选):https://www.python.org/ftp/python/一、添加阿里云第三方扩展源仓库(安装拓展源仓库才能安装yum安装openssl11openssl11-devel,python源码编译必须要openssl11或以上版本)备注,我这里是把pyhto......
  • 解决jar文件不显示图标问题(配置环境变量仍不显示)
    配置环境变量后不显示Java图标,右键选择打开方式仍不管用,使用以下方法1.右键jar包,点击属性2.点击更改3.划到底端,点击电脑上选择应用4.找到JDK文件中的bin目录中的java.exe文件打开,最后点击是设置默认值以及确定就可以啦小白一枚,如果对大家有用的话给个赞......
  • Java基本数据类型转换
    一、自动类型转换1.基本介绍当Java程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换数据类型按精度(容量)大小进行排序为:![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/520b6288a88540b0ace9d2c22b844ca4.pngpublicclass......
  • java的数据类型
    java是一门强语言类型Java的数据类型分为两大类1.基本类型(primitivetype)强制转换类型会有内存溢出或者精度丢失问题,不能对boolean类型进行强制转换不能把对象类型转换位不相干的类型整数int类型拓张二进制0b八进制0十六进制0xfloat存在舍入误差问题,最好完全避免使......
  • 图解Redis 04 | Set数据类型的原理及应用场景
    介绍Redis的Set类型是一个不允许重复元素的集合,元素存储的顺序不按照插入的顺序,因此属于无序集合。一个Set最多可以存储2^32-1个元素,这与数学中的集合概念类似。Set类型不仅支持增、删、改、查等操作,还支持多个Set之间的交集、并集和差集运算。内部实现Set类......
  • 为什么有了基本类型还需要包装类?
    引言在Java编程语言中,数据类型分为两种:基本类型(PrimitiveType)和包装类(WrapperClass)。基本类型包括int、char、boolean等,它们是最基础的数据类型,直接存储值。而包装类则是这些基本类型的对象化版本,如Integer、Character、Boolean等。许多Java初学者可能会疑惑:既然有了基本......
  • C语言初学:常量和变量
    常量整型常量实型常量字符常量用一对单引号将一个字符括起来。字符串常量由一对双引号引起将零个或多个字符序列括起来。变量变量的输入与输出标准格式转换将标准日期格式YYYY-MM-DD转换为中国美国英国三个国家的三种日期格式代码如下:输出公民身份证号码的各组成......
  • 42 C 语言 typedef:为基本数据类型、数组、指针、结构体、共用体起别名
    目录1 typedef介绍2 为某个基本类型起别名2.1为int类型起别名Integer2.2为unsignedchar类型起别名Byte2.3为基本类型一次起多个别名3 为结构体、共用体起别名3.1为结构体起别名3.1.1分开定义结构体和别名3.1.2与结构体定义一起使用typedef3.1.3为......
  • Stata教程:高级虚拟变量处理和标签添加
    Stata教程:高级虚拟变量处理和标签添加小菲stata,全网同名Hello,大家好,接粉丝提问,这期给大家分享虚拟变量处理和标签添加,在这个教程中,我们将使用Stata的"nlsw88"数据集(这是一个关于1988年美国女性劳动力的数据集)来演示如何创建更复杂的虚拟变量,添加详细的标签,并进行基本的统......
  • Redis的五种基本类型和业务场景和使用
    目录Redis是什么?Redis的特点依赖配置redis的配置类(用于格式转换,处理乱码)String(字符串)特点业务场景代码使用案例List(列表)特点业务场景代码使用案例Set(集合)特点业务场景代码使用案例Hash(哈希表)特点业务场景代码使用案例SortedSet(有序集合)特点业务场景......