rust数据类型

目录

一,基本类型

1,基本类型

(1)整数类型

(2)浮点数

(3)bool类型

(4)char类型

2,基本类型的代数结构

二,复合类型

1,序列、单元序列、切片

2,元组、单元元组

3,结构体、空结构体、单元结构体

4,元组结构体、单元元组结构体

5,枚举

(1)枚举的成员

(2)整型值的显式声明

(3)整型值的隐式推导

(4)直接使用枚举值

(5)把枚举值转换成整数

6,数据大小

(1)基本类型

(2)序列、单元序列、切片、空切片、元组、单元元组、枚举

(3)结构体、空结构体、单元结构体、元组结构体、单元元组结构体

(4)指针、字符串


一,基本类型

1,基本类型

(1)整数类型

cpp 复制代码
	let x=111_222_3334;
	let y:u16=1123;

整数默认是i32类型,整数中间的下划线可以忽略。

(2)浮点数

在 Rust 中浮点类型数字也有两种基本类型: f32f64

cpp 复制代码
	let x=2.5;
	let y:f32=1.23;

浮点数默认是f64类型。

浮点数都有唯一的非自反元素NAN,所以std里面判断一个数是不是NAN的源码是这么写的:

cpp 复制代码
    pub const fn is_nan(self) -> bool {
        self != self
    }

(3)bool类型

取值:false true

(4)char类型

cpp 复制代码
    let heart_eyed_cat:char = '😻';
    println!("{}",heart_eyed_cat);
    let z:char = '我';
    println!("{}",z);

rust的char类型范围比较大,中文甚至emoji都算,char类型大小为4个字节。

char类型大小为什么是为4个字节?

因为rust字符串采用utf-8编码,而utf-8一个字符最多占4个字节。

char和整数互转规则:

u8可以用as转为char,u16和u32都不行,而char可以用as转为u8和u16和u32

cpp 复制代码
    let x:u8=100;
    let c=char::from(x);
    let x:u32=100;
    let c2=char::from_u32(x);
    assert_eq!(c2,Some(c));
    let c3=char::try_from(x);
    assert_eq!(c3,Ok(c));

2,基本类型的代数结构

在c++中,基本类型都是有等价关系的。

然而在rust中,浮点数只有部分等价关系,没有等价关系,Rust 的整数类型、字符串类型、布尔类型都有等价关系。

所以,哈希表的key类型可以是整数类型、字符串类型、布尔类型,不能是浮点数类型。

二,复合类型

1,序列、单元序列、切片

序列,也称为数组

(1)自动生成序列:

序列相当于是整数的复合类型。

cpp 复制代码
	for i in 1..=5{	
	    println!("{}",i);
	}

带了等号,所以序列是1,2,3,4,5

去掉等号,序列就是1,2,3,4

(2)普通序列、切片

cpp 复制代码
fn main() {
    let mut c = [1,2,3,4,8,6];
    let slice = &mut c[1..3];
    slice[0]=9;
    assert_eq!(c,[1,9,3,4,8,6]);
}

c就是普通序列(数组),slice就是切片

(3)单元序列

单元序列就是空序列:

cpp 复制代码
    let mut x =Vec::from([]);
    x.push(5);

2,元组、单元元组

(1)元组

cpp 复制代码
    let t = (1,1.5,"what");
    assert_eq!(t.0, 1);
    assert_eq!(t.1, 1.5);
    assert_eq!(t.2, "what");

(2)单元元组

单元元组就是空元组,有2种用法,一是用于没有返回值的函数:

cpp 复制代码
fn f() {
    print!("{}",123);
}
fn f2()->() {
    print!("{}",123);
}
fn f3()->(){
    print!("{}",123);
    return ();
}

二是用作map的值,表示不关心值,只关心key。

cpp 复制代码
fn main() {
    let mut map = HashMap::new();
    assert_eq!(map.insert(3, ()), None);
    assert_eq!(map.insert(5, ()), None);
}

3,结构体、空结构体、单元结构体

(1)结构体

cpp 复制代码
#[derive(PartialEq, Eq, Clone, Debug)]
struct S{
    x:i32,y:i32
}
fn main() {
    let s1=S{y:1, x:2};
    let s2=S{x:3,..s1};
    assert_eq!(s2,S{x:3,y:1});
    println!("end");
}

创建结构体实例时,必须写明成员名:成员值,所以顺序也叫无所谓了。

(2)2种省略写法

省略写法一:可以根据一个结构体实例创建另一个结构体实例,除了写明的成员,其他成员用相同值进行初始化。

cpp 复制代码
struct Pointer{
    x:i32,
    y:i32
}
fn main() {
    let a=Pointer{x:3,y:4};
    let p=Pointer{x:5,..a};
    assert_eq!(5,p.x);
    assert_eq!(4,p.y);
}

其中..a表示从a抄录部分成员值,..a必须写在最后面

省略写法二:可以把形如x:x简写成x,必须完全同名时才可以简写。

cpp 复制代码
struct Pointer{
    x:i32,
    y:i32
}
fn main() {
    let x=5;
    let a=Pointer{x:x,y:4};
    let p=Pointer{x,y:4};
    assert_eq!(5,p.x);
    assert_eq!(4,p.y);
    let p=Pointer{y:4,x};
    assert_eq!(5,p.x);
    assert_eq!(4,p.y);
}

小结:

..a必须写在最后面,其他的成员赋值无论先后,每一个都可以按照名字严格对应。

(3)空结构体

cpp 复制代码
struct S{}

fn main(){
    let a=S{};
    //let b=S; //error
}

(4)单元结构体

单元结构体的定义最简洁,只有一个名字:

cpp 复制代码
struct S2;

fn main(){
    let c=S2{};
    let d=S2;
}

4,元组结构体、单元元组结构体

(1)元组结构体

元组结构体就是又像元组又像结构体的一种数据结构,语法和元组和结构体都不一样。

cpp 复制代码
struct Point(i32, i32, i32);

fn main() {
    let x = Point(3,0,0);
    assert_eq!(x.0, 3);
}

PS:结构体成员是必须按照名字对应,顺序无所谓,元组结构体是必须按照顺序对应,没有名字。

(2)单元元组结构体

cpp 复制代码
struct S();

fn main() {
    let x=S();
    print!("end");
}

5,枚举

枚举的BNF:

Enumeration :

enum IDENTIFIER GenericParams? WhereClause? { EnumItems ? }

EnumItems :

EnumItem ( , EnumItem )* ,?

EnumItem :

OuterAttribute * Visibility?

IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?

EnumItemTuple :

( TupleFields? )

EnumItemStruct :

{ StructFields? }

EnumItemDiscriminant :

= Expression

也就是说,枚举的成员可以有3种类型随意组合,分别是元组tuple,结构体,还有表达式

虽然说单个整型变量也是表达式,但是枚举里面的表达式好像只能是整型变量。

(1)枚举的成员

细分下来一共是五种:

cpp 复制代码
enum Enum0 {
    Tuple1(),
    Tuple2(i32,f32),
    Struct1{},
    Struct2{x:i32,y:f64},
    X,
}

五个成员分别是单元元组,元组结构体,单元结构体,结构体,整型变量。

所有的枚举成员,都对应一个整型值,默认是isize类型,允许编译器采用更小的整数类型。

(2)整型值的显式声明

前提条件:要么只有整型变量,要么用repr显式声明了枚举整数类型。

cpp 复制代码
enum Enum1 {
    X=7,
    Y,
    Z=-100
}

#[repr(u8)]
enum Enum2 {
    Tuple1(),
    Tuple2(i32,f32),
    Struct1{},
    Struct2{x:i32,y:f64},
    X=200,
}

(3)整型值的隐式推导

推导规则:从有显式声明的,往下依次加一,如果第一个成员没有声明,那就是0

推导失败就编译失败:按照推导规则发现有重复值的(包括显式声明重复值的),或者推导值超出了整数范围的,就编译失败

(4)直接使用枚举值

最简单的例子:

cpp 复制代码
#[derive(Debug,PartialEq)]
enum Enum {
    X=200,
}

fn main() {
    let x=Enum::X;
    assert_eq!(Enum::X, x);
}

Debug和PartialEq都是必须声明的。

复杂一点的例子:

cpp 复制代码
#[repr(u8)]
#[derive(Debug,PartialEq)]
enum Enum {
    Tuple1()=3,
    Tuple2(i32,i64),
    Struct0{},
    Struct1{},
    Struct2{x:i32,y:i64}=100,    
    X=200,
}

fn main() {
    let x1 = Enum::Tuple1();
    let x2 = Enum::Tuple2(5,6);
    let x3=Enum::Struct0{};
    let x4=Enum::Struct1{};
    let x5=Enum::Struct2{x:7,y:8};
    let x6=Enum::X;
    assert_eq!(Enum::Tuple1(), x1);
    assert_eq!(Enum::Tuple2(5,6), x2);
    assert_ne!(x1,x2);
    assert_eq!(Enum::Struct0{}, x3);
    assert_ne!(x3,x4);
    assert_eq!(Enum::Struct2{x:7,y:8}, x5);
    assert_ne!(Enum::Struct2{x:9,y:9}, x5);
    assert_eq!(Enum::X, x6);
}

Enum里面2个单元结构体是不相等的。

对于2个枚举变量对应的是Enum里面同一个枚举值的,比如都是Struct2,还需要里面的成员相等,2个枚举变量才完全相等。

(5)把枚举值转换成整数

前提条件:只由单元元组、单元结构体、整型变量构成,且只有整型变量有显示声明整型值。

cpp 复制代码
#[repr(u8)]
enum Enum {
    Tuple1(),
    X=100,
    Tuple2(),
    Struct0{},
    Y=200,
    Struct1{},    
}

fn main() {
    assert_eq!(Enum::Tuple1() as u8, 0);
    assert_eq!(Enum::X as u8, 100);
    assert_eq!(Enum::Tuple2() as u8, 101);
    assert_eq!(Enum::Struct0{} as u8, 102);
    assert_eq!(Enum::Y as u8, 200);
    assert_eq!(Enum::Struct1{} as u8, 201);
}

6,数据大小

use std::mem::size_of;

use std::mem::size_of_val;

(1)基本类型

cpp 复制代码
fn main() {
    assert_eq!(size_of::<i8>(),1);
    assert_eq!(size_of::<u8>(),1);
    assert_eq!(size_of::<i16>(),2);
    assert_eq!(size_of::<u16>(),2);
    assert_eq!(size_of::<i32>(),4);
    assert_eq!(size_of::<u32>(),4);
    assert_eq!(size_of::<i64>(),8);
    assert_eq!(size_of::<u64>(),8);
    assert_eq!(size_of::<i128>(),16);
    assert_eq!(size_of::<u128>(),16);
    assert_eq!(size_of::<f32>(),4);
    assert_eq!(size_of::<f64>(),8);
    assert_eq!(size_of::<bool>(),1);
    assert_eq!(size_of::<char>(),4);
    println!("end");
}

(2)序列、单元序列、切片、空切片、元组、单元元组、枚举

cpp 复制代码
enum Enum {
    X=253,
    Y,
    Z
}
enum Enum2 {
    X=254,
    Y,
    Z
}

fn main() {
    let x=[false,true];//序列=单个尺寸*个数
    assert_eq!(size_of_val(&x),2);
    let x:[bool;0]=[];
    assert_eq!(size_of_val(&x),0);//单元序列=固定0
    let y=&x[..];
    assert_eq!(size_of_val(&y),16);//切片=固定16
    let y=&x[0..0];
    assert_eq!(size_of_val(&y),16);//空切片也是16
    let z=(false,1);
    assert_eq!(size_of_val(&z),8);//元组 4+4
    let z=(1,false,y);
    assert_eq!(size_of_val(&z),24);//元组 4+4+16
    let z=();
    assert_eq!(size_of_val(&z),0);//单元元组=固定0
    assert_eq!(size_of::<Enum>(),1);//枚举的大小等于最大枚举值的大小
    assert_eq!(size_of::<Enum2>(),2);
    println!("end");
}

其中,元组的规则应该是等同于普通结构体。

(3)结构体、空结构体、单元结构体、元组结构体、单元元组结构体

结构体的大小计算涉及到对齐值的概念,这一部分和C相同,具体细节参考结构体大小和对齐值

不同的是,rust中的结构体默认会自动重排,如果加了#repr(C)属性宏则不会重排

cpp 复制代码
struct S1{
    a:u32,
    b:u16,
    c:u8,
}
struct S2{
    b:u16,
    a:u32,
    c:u8,
}
#[repr(C)]
struct S3{
    b:u16,
    a:u32,
    c:u8,
}

struct S4{}
struct S5;
struct S6(i32,bool);
struct S7();

fn main() {
    assert_eq!(size_of::<S1>(),8);//普通结构体
    assert_eq!(size_of::<S2>(),8);//重排结构体
    assert_eq!(size_of::<S3>(),12);//禁止重排的普通结构体
    assert_eq!(size_of::<S4>(),0);//空结构体=固定0
    assert_eq!(size_of::<S5>(),0);//单元结构体=固定0
    assert_eq!(size_of::<S6>(),8);//元组结构体 4+4
    assert_eq!(size_of::<S7>(),0);//单元元组结构体=固定0
    println!("end");
}

(4)指针、字符串

cpp 复制代码
​
fn main() {
    let p=&1 as *const i32;
    let psize = size_of_val(&p);// psize=4或者8,看机器
    let a=&1;
    assert_eq!(size_of_val(&a),psize);//普通引用等同于指针
    let b=&[1,2];
    assert_eq!(size_of_val(&b),psize);//引用数组是普通引用,所以等同于指针
    let c=&b[..];
    assert_eq!(size_of_val(&c),psize*2);//引用切片是胖指针,等同于2个指针
    let s:&str="123";
    assert_eq!(size_of_val(&c),psize*2);//&str是引用切片,所以是胖指针
    let s=String::from("12345678");
    assert_eq!(size_of_val(&s),size_of::<Vec<u8>>());//String对象的大小是固定的,和内部数据长度无关
    println!("end");
}

​

在64位机器上,String是24个字节。

相关推荐
北城以北888810 小时前
RocketMQ简介
java·spring boot·后端·rocketmq
天天进步201511 小时前
Python全栈项目--基于机器学习的异常检测系统
开发语言·python·机器学习
GoGeekBaird18 小时前
从 Prompt Engineering 到 Loop Engineering,我觉得 AI 开发这事儿终于开始变味了
后端·github
xxie12379418 小时前
return与print
开发语言·python
秋918 小时前
从 Python 后端工程师转型 AI Engineer(AI 工程化)的完整补课清单(2026实战版)
开发语言·人工智能·python
一条泥憨鱼18 小时前
【Redis】数据类型和常用命令
java·数据库·redis·后端·缓存
程序员二叉18 小时前
【Java】 异常高频面试题精讲 | 易错点+对比总结
java·开发语言·面试
慕木沐19 小时前
Google ADK Java 1.0版本 核心机制与实战 Demo
java·开发语言·python
Oneslide19 小时前
初始化微信小程序
后端
Roann_seo%19 小时前
C++文件操作完全指南:从文本读写到二进制文件处理
开发语言·c++