侧边栏壁纸
博主头像
博主等级

秋风清,秋月明,落叶聚还散,寒鸦息复惊,相思相见知何日,此时此夜难为情!

  • 累计撰写 20 篇文章
  • 累计创建 32 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Rust数据类型

尘
2024-01-21 / 0 评论 / 0 点赞 / 91 阅读 / 23621 字
温馨提示:
本文最后更新于 2024-01-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Rust数据类型

Rust是静态编译语言,在编译时必须知道变量的具体类型

  • 基于使用的值,编译器通常能推断出它的具体类型
  • 如果可能的类型比较多(例如使用parse方法可能转成多种数据类型),就必须添加类型的标注,否则编译会报错

数值类型

Rust的数值类型包括整数和浮点数。有如下几种类型:

长度有符号无符号浮点数
8-biti8u8
16-biti16u16
32-biti32 (整型数据的默认值)u32f32
64-biti64u64f64(浮点数据类型的默认值)
128-biti128u128
arch (根据机器确定)isizeusize

整数类型

整数类型没有小数部分

无符号整数类型以u开头

有符号整数类型以i开头

浮点类型

浮点数据类型有f32f64两种。其中f64数浮点数据的默认数据类型。

let sun = 5 + 10; // 数据类型:i32
let subtraction = 95.5 - 1 as f64; // 数据类型:f64。使用了as f64将整数强制转换为浮点数类型
let multiplication = 32 * 5; // 数据类型:i32
let division = 100f64 / 2.3; // 数据类型:f64  100f64 或者 100_f64 作用与 100 as f64 一样
let remainder = 100 % 3; // 数据类型:i32

可以在数值字面量后加上类型来表示该类型的数值。例如:

fn main(){
  let a = 33i32;    // 直接加类型后缀
  let b = 33_i32;   // 使用_分隔数值和类型
  let c = 33_isize;
  let d = 33_f32;
}

如果数值较长,可以在任意位置处使用下划线_划分数值,增加可读性。

fn main(){
  let a = 33_333_33_i32;
  let b = 3_333_333_i32;
  let c = 3_333_333f32;
}

当不明确指定变量的类型,也不明确指定数值字面量的类型后缀,Rust默认将整数当作i32类型,浮点数当作f64类型

fn main(){
  // 等价于 let a: i32 = 33_i32;
  let a = 33;
  
  // 等价于let b: f64 = 64.123_f64;
  let b = 64.123;
}

每种数值类型都有所能存储的最大数值和最小数值。当超出类型的有效范围时,Rust将报错(panic)。例如u8类型的范围是0-255,它无法存储256。

fn main() {
  let n: i32 = std::i32::MAX;  // i32类型的最大值
  println!("{}", n + 1);     // 编译错误,溢出
}

Rust允许使用0b 0o 0x来表示二进制、八进制和十六进制的整数

fn main(){
  let a = 0b101_i32;  // 二进制整数,i32类型
  let b = 0o17;       // 八进制整数,i32类型
  let c = 0xac;       // 十六进制整数,i32类型
  println!("{}, {}, {}", a, b, c);  // 5, 15, 172
}

布尔类型

  • 布尔数据类型只有两个值:truefalse
  • 布尔数据类型占据一个字节大小
  • 符号是bool
let t = true; // 数据类型:bool,通过推断得出t的数据类型是bool
let f: bool = false; // 数据类型:bool,显示指定数据类型为bool

在Rust中,布尔值可以使用as操作符转换为整型数据类型,false对应0true对应1。但数值类型不允许转换为bool值。bool 类型不能直接转换为浮点数类型。Rust的类型系统不允许直接在这两种不同的基本类型之间进行隐式或显式的转换。

再次提醒,as操作符常用于原始数据类型之间的类型转换。

fn main() {
    println!("{}", true as u32); // 1
    println!("{}", false as u8); // 0
    // println!("{}", 1_u8 as bool);  // 编译错误 cannot cast `u8` as `bool`
    // println!("{}", false as f64); // casting `bool` as `f64` is invalid
}

char类型

char类型是Rust的一种基本数据类型,用于存放单个unicode字符,占用4字节空间(32bit)。

在存储char类型数据时,会将其转换为UTF-8编码的数据(即Unicode代码点)进行存储。

char字面量是单引号包围的任意单个字符,例如'a'、'我'

注意:char和单字符的字符串String是不同的类型。

允许使用反斜线对某些特殊字符转义:

字符名      字节字面量
--------------------
单引号      '\''
反斜线      '\\'
换行符      '\n'
换页符      '\r'
制表符      '\t'

Rust不会自动将char类型转换为其他类型,但可以进行显式转换:

  • 可使用as将char转为各种整数类型,目标类型小于4字节时,将从高位截断
  • 可使用asu8类型转char
    • 之所以不支持其他整数类型,是因为其他整数类型的值可能无法转换为char(即不在UTF-8编码表范围的整数值)
  • 可使用std::char::from_u32u32整数类型转char,返回值Option<char>
    • 如果传递的u32数值不是有效的Unicode代码点,则from_u32返回None
    • 否则返回Some(c)c就是char类型的字符
  • 可使用std::char::from_digit(INT, BASE)将十进制的INT转换为BASE进制的char
    • 如果INT参数不是有效的进制数,返回None
    • 如果BASE超出进制数的合理范围[1,36],将panic
    • 否则返回Some(c)c就是char类型的字符

例如:

// 可以存储甚至一个emoji
let x = 'Z';
let y: char = '😈';
let z = 'ㅞ';
// char -> Integer
println!("{}", '我' as i32);     // 25105
println!("{}", '是' as u16);     // 26159
println!("{}", '是' as u8);      // 47,被截断了

// u8 -> char
println!("{}", 97u8 as char);    // a

// std::char
use std::char;

println!("{}", char::from_u32(0x2764).unwrap());  // ❤
assert_eq!(char::from_u32(0x110000), None);  // true

println!("{}", char::from_digit(4,10).unwrap());  // '4'
println!("{}", char::from_digit(11,16).unwrap()); // 'b'
assert_eq!(char::from_digit(11,10),None); // true

tuple类型(元组)

  • tuple可以存放0个、1个或多个任意数据类型的数据
  • tuple的长度是固定的:一旦声明就无法改变。

创建tuple

  • 在小括号里,将各个值用逗号隔开
  • 在tuple中每个位置都对应一个数据类型,tuple中的各个元素数据类型不必相同。
let tup = (500, 6.4, 1, false); // 元组: 自动类型推断:(i32, f64, i32, bool)

有时候tuple里只会保存一个元素,此时必须不能省略最后的逗号:

let p = ("hello",);

获取tuple的元素值

  • 可以使用模式匹配来解构一个tuple来获取元素的值。

    fn main() {
        let tup = (500, 6.4, 1, false); // 元组: 自动类型推断:(i32, f64, i32, bool)
    
        // 通过解构赋值,可以将元组中的元素分别赋值给变量
        let (a, b, c, d) = tup;
        println!("a = {}, b = {}, c = {}, d = {}", a, b, c, d);
    
        // let (x, y, z) = tup; // expected a tuple with 4 elements, found one with 3 elements
        let (x, y, _, z) = tup;
        println!("x = {}, y = {}, z = {}", x, y, z);
    }
    

    在Rust中,如果在解构时获取的参数数量少于元组的元素数量,会报错如:mismatched types, 这是因为,解构元组时,通常我们期望获取所有元组中的元素,而缺少的部分可能导致未使用的值或潜在的错误。

    可以通过使用下划线 _ 来表示未使用的变量,以避免产生未使用的值的警告。

    在这个例子中,通过使用 _ 来表示第三个元素,我们告诉编译器我们有意不使用该元素,从而消除了报错。

  • 使用.标记法,后接元素的索引号

    fn main() {
        let tup = (500, 6.4, 1, false); // 元组: 自动类型推断:(i32, f64, i32, bool)
        println!("tup = ({},{},{},{})", tup.0, tup.1, tup.2, tup.3);
        let a: usize = 2;
        // println!("{}", tup.a);  // 错误
    }
    

    访问tuple元素的索引必须是编译期间就能确定的数值,而不能是变量。

unit类型

不保存任何数据的tuple表示为()。在Rust中,它是特殊的,它有自己的类型:unit。

unit类型的写法为(),该类型也只有一个值,写法仍然是()。参考下面的写法应该能搞清楚。

// 将值()保存到类型为()的变量x中
//    类型    值
let x: ()  =  ();

unit类型通常用在那些不关心返回值的函数中。在其他语言中,那些不写return语句或return不指定返回内容的的函数,一般表示不关心返回值。在Rust中可将这种需求写为return ()

Array类型

数组的用处

  • 如果想让你的数据存放在 stack ( )上而不是 heap(堆)上,或者想保证有固定数量的元素,这时使用数组更有好处。

  • 数组没有Vector灵活

    • Vector和数组类似,由标准库提供
    • Vector的长度可变
    • 如果不确定应该使用数组还是Vector,那大概率推荐Vector
  • 数组长度固定
  • 元素类型相同

数组的数据类型表示方式为[Type; N],其中:

  • Type是该数组要存储什么类型的数据,数组中的所有元素类型都必须是Type
  • N是数组的长度,Rust不会自动伸缩数组的长度

数组字面量使用中括号[]表示,例如[1,2,3]。还有一种特殊的表示数组字面量的方式是[val; N],这有点像数组类型的描述方式[Type; N],不过这里表示的是该数组长度为N,并且这N个元素的值都初始化为val。

[Type; N]是用来描述数据类型的,所以其中的N必须在编译期间就能确认,因此N不能是一个变量

意味着无法像Java这样:

int size = 1024;
int[] array = new int[size];

声明数组

fn main() {
    // 自动推导类型为:[i32; 4]
    let _arr = [11, 22, 33, 44];

    // 自动推导类型为:[u8; 1024]
    // 该数组初始化为1024个u8类型的0
    // 可将之当作以0填充的1K的buf空间
    let _arr2 = [0_u8; 64];
    println!("arr = {:?}\narr2 = {:?}", _arr, _arr2);

    let _arr3 = [4; 6];
    println!("arr3 = {:?}", _arr3);
}

执行结果:

arr = [11, 22, 33, 44]
arr2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
arr3 = [4, 4, 4, 4, 4, 4]

数组访问

fn main() {
    let months = ["January", "February", "March", "April",
        "May", "June", "July", "August",
        "September", "October", "November", "December"];
    for i in 0..months.len() {
        println!("{}: {}", i + 1, months[i]);
    }

    println!("{}", months[11]);
    // 编译可以通过,但运行会报错
    // println!("{}", months[13]); // index out of bounds: the length is 12 but the index is 13
}

可以迭代数组,不过不能直接for i in arr{},而是for i in &arr{}或者for i in arr.iter(){}。例如:

fn main(){
  let arr = [11,22,33,44];
  for i in arr.iter() {
    println!("{}", i);
  }
}

数组有很多方法可以使用,例如len()方法可以获取数组的长度。

fn main(){
  let arr = [11,22,33,44];
  println!("{}", arr.len());    // 4
}
0

评论区