目录
一,基本类型
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)整数类型
let x=111_222_3334;let y:u16=1123;
整数默认是i32类型,整数中间的下划线可以忽略。
(2)浮点数
在 Rust 中浮点类型数字也有两种基本类型: f32
和 f64
let x=2.5;let y:f32=1.23;
浮点数默认是f64类型。
浮点数都有唯一的非自反元素NAN,所以std里面判断一个数是不是NAN的源码是这么写的:
pub const fn is_nan(self) -> bool {self != self}
(3)bool类型
取值:false true
(4)char类型
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
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)自动生成序列:
序列相当于是整数的复合类型。
for i in 1..=5{ println!("{}",i);}
带了等号,所以序列是1,2,3,4,5
去掉等号,序列就是1,2,3,4
(2)普通序列、切片
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)单元序列
单元序列就是空序列:
let mut x =Vec::from([]);x.push(5);
2,元组、单元元组
(1)元组
let t = (1,1.5,"what");assert_eq!(t.0, 1);assert_eq!(t.1, 1.5);assert_eq!(t.2, "what");
(2)单元元组
单元元组就是空元组,有2种用法,一是用于没有返回值的函数:
fn f() {print!("{}",123);
}
fn f2()->() {print!("{}",123);
}
fn f3()->(){print!("{}",123);return ();
}
二是用作map的值,表示不关心值,只关心key。
fn main() {let mut map = HashMap::new();assert_eq!(map.insert(3, ()), None);assert_eq!(map.insert(5, ()), None);
}
3,结构体、空结构体、单元结构体
(1)结构体
#[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种省略写法
省略写法一:可以根据一个结构体实例创建另一个结构体实例,除了写明的成员,其他成员用相同值进行初始化。
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,必须完全同名时才可以简写。
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)空结构体
struct S{}fn main(){let a=S{};//let b=S; //error
}
(4)单元结构体
单元结构体的定义最简洁,只有一个名字:
struct S2;fn main(){let c=S2{};let d=S2;
}
4,元组结构体、单元元组结构体
(1)元组结构体
元组结构体就是又像元组又像结构体的一种数据结构,语法和元组和结构体都不一样。
struct Point(i32, i32, i32);fn main() {let x = Point(3,0,0);assert_eq!(x.0, 3);
}
PS:结构体成员是必须按照名字对应,顺序无所谓,元组结构体是必须按照顺序对应,没有名字。
(2)单元元组结构体
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)枚举的成员
细分下来一共是五种:
enum Enum0 {Tuple1(),Tuple2(i32,f32),Struct1{},Struct2{x:i32,y:f64},X,
}
五个成员分别是单元元组,元组结构体,单元结构体,结构体,整型变量。
所有的枚举成员,都对应一个整型值,默认是isize类型,允许编译器采用更小的整数类型。
(2)整型值的显式声明
前提条件:要么只有整型变量,要么用repr显式声明了枚举整数类型。
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)直接使用枚举值
最简单的例子:
#[derive(Debug,PartialEq)]
enum Enum {X=200,
}fn main() {let x=Enum::X;assert_eq!(Enum::X, x);
}
Debug和PartialEq都是必须声明的。
复杂一点的例子:
#[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)把枚举值转换成整数
前提条件:只由单元元组、单元结构体、整型变量构成,且只有整型变量有显示声明整型值。
#[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)基本类型
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)序列、单元序列、切片、空切片、元组、单元元组、枚举
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);//单元序列=固定0let y=&x[..];assert_eq!(size_of_val(&y),16);//切片=固定16let y=&x[0..0];assert_eq!(size_of_val(&y),16);//空切片也是16let z=(false,1);assert_eq!(size_of_val(&z),8);//元组 4+4let z=(1,false,y);assert_eq!(size_of_val(&z),24);//元组 4+4+16let z=();assert_eq!(size_of_val(&z),0);//单元元组=固定0assert_eq!(size_of::<Enum>(),1);//枚举的大小等于最大枚举值的大小assert_eq!(size_of::<Enum2>(),2);println!("end");
}
其中,元组的规则应该是等同于普通结构体。
(3)结构体、空结构体、单元结构体、元组结构体、单元元组结构体
结构体的大小计算涉及到对齐值的概念,这一部分和C相同,具体细节参考结构体大小和对齐值。
不同的是,rust中的结构体默认会自动重排,如果加了#[repr(C)]属性宏则不会重排。
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);//空结构体=固定0assert_eq!(size_of::<S5>(),0);//单元结构体=固定0assert_eq!(size_of::<S6>(),8);//元组结构体 4+4assert_eq!(size_of::<S7>(),0);//单元元组结构体=固定0println!("end");
}
(4)指针、字符串
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个字节。