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个字节。

相关推荐
闲晨2 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程29 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk1 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*1 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue1 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man2 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸3 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农3 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库