Rust系列(一)变量、常量及基础数据类型

Posted by YaPi on February 15, 2022

Rust变量

rust中变量用let定义,区别于其他编程语言,rust的变量是不可变的。比如:

fn main(){
    let x=5;
    x=6; // ERROR 
}

若需要定义一个可变的变量,需要使用关键字 ‘mut’

fn main(){
    let mut x = 5;
    x = 6;
}

同时,rust中变量具有’隐藏’的特性,后定义的同名变量会覆盖前一个变量的值。

fn main(){
    let x = 5;
    let x = 6;
    print!(x); // 6
}

可在定义时指定类型

fn main(){
    let x:i32 = 5;
}

常量

rust中常量使用关键字 const定义,定义后不允许修改。

const A_CONST:i32 = 42;

基础上数据类型

整数

长度 | 有符号 | 无符号 —|—|— 8 | i8 | u8 16 | i16 | u16 32 | i32 | u32 64 | i64 | u64 128 | i128 | u128 arch | isize | usize

对于未明确标注类型的整数,Rust默认采用i32。同时 isize和usize根据系统不同而有不同的长度。

浮点数

Rust有两种浮点类型为 f32 和 f64。默认采用 f64

fn main(){
    let x = 2.0;
    let y:f32 = 4.0;
}
bool

bool与其他语言一样,true和false。不能转换为0或1。

fn main(){
    let mut x:bool = false;
}

元组

元组是将多个具有各种类型的值组合成一个符合类型的通用方法。元组有固定长度,一旦声明它们的大小 就不能增长或收缩。

fn main() {
    let a:i32 = 10;
    let b:char = 'A';
    // 元组定义
    // 可以类型不相同
    let myTuple:(i32,char) = (a,b);
    // 解元组
    let (c,d) = myTuple;
    println!("c = {} d = {}",c ,d); // c = 10 d = A
    // 使用下标获取具体值
    println!("myTuple.0 = {}",myTuple.0); // myTuple.0 = 10
    println!("myTuple.1 = {}",myTuple.1); // myTuple.1 = A

    let (result,is_overflow) = a.overflowing_add(10);// 20 false
    println!("{} {}",result, is_overflow);
}

数组

数组中的每个元素都必须具有相同的类型,具有固定长度,数组下标从0开始,同时存在越界检查。

fn main() {
    let arr:[u32;5] = [1,2,3,4,5];

    println!("arr[1] = {}",arr[1]);
    // 将字符串4强制转换成usize类型,同时发生了错误程序就不再运行
    let index = "4".parse::<usize>().unwrap();
    println!("arr[1] = {}",arr[index]);

    // 声明一个32 * 1024 大小的缓冲
    let mut my_buffer:[u32;32 * 1024] = [0;32 * 1024];
    println!("my_buffer = {}",my_buffer[32*1024-1]);
    
    // 直接修改数组中的元素会报错,需要将数组声明为可变类型 mut
    my_buffer[32*1024-1] = 13;
    println!("my_buffer = {}",my_buffer[32*1024-1]);

}

切片

切片类型是对一个数组(包括固定大小的数组和动态数组的引用片段),有利于安全有效地访问数组的一部分。 而不需要拷贝数组或数组中的内容,切片在编译的时候其长度是未知的,在底层实现上,一个切片保存着两个 usize成员,第一个usize成员指向切片起始未知的指针,第二个usize成员表示切片长度。创造切片的的两个参数不能是负数。

fn main() {
    let arr:[u32;5] = [1,2,3,4,5];
    // .. 是rust的 Range语法 & 是引用符号
    // 切片取值为左闭右开
    let slice = &arr[0..3];
    println!("slice[0]= {} length = {}",slice[0],slice.len());
    let last = &arr[3..arr.len()];
    println!("last[0]= {} last = {}",last[0],last.len());
    // slices是否为空
    // slice.is_empty();
}

结构体

结构体是多种不同数据类型的组合,可以为每个成员命名,可以使用struct关键字创建三种类型的结构。

  • 元组结构
  • 经典c结构
  • 无字段的单元结构

结构体使用驼峰命名

// 元组
struct Pair(i32, f32);
// 标准c结构
#[derive(Debug)] // 派生属性 加上此代码,以便于可以直接在println中打印
struct Person{
    name: String,
    age: u8,
}

// 单元结构
struct Unit;

fn main() {
    let pari = Pair(10,10.0);
    // 使用 . 获取值
    println!("{} {}",pari.0,pari.1);

    let tom = Person{
        name: String::from("jack"),
        age: 18,
    };
    println!("{} {}",tom.name,tom.age);
    // 直接打印tom会报错,println!("{}",tom)
    println!("{:?}",tom)
}

// out
// 10 10
// jack 18
// Person { name: "jack", age: 18 }

枚举

  • 无参枚举
  • 带枚举值的枚举
  • 带参数的枚举
// 无参枚举
enum T {A,B,C}
// 带枚举值的枚举
enum B {
    A = 1,
    B = 3,
    D = 4
}
// 带参数的枚举
enum IPAddr {
    IPv4(u8,u8,u8,u8),
    IPv6(u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8,u8)
}
fn main() {
    let localhost:IPAddr = IPAddr::IPv4(127,0,0,1);
    // 模式匹配
    // 相当于解封装
    match localhost{
        IPAddr::IPv4(a,b,c,d) => {
            println!("{} {} {} {}",a,b,c,d)
        }
        _ => {}
    }
}

类型强制转换

rust是强类型语言,无默认类型转换(c++中可以)。在需要类型转换的时候有两种方法。 第一种是as关键字,这种方式可允许安全的转化。另一种是transmute关键字。

use std::mem;
fn main() {
    // 报错
    // let a = [0u8,1u8,0u8,0u8];
    // let b:u32 = a as u32;
    // println!("{}",b);
    
    unsafe {
        let a = [0u8,1u8,0u8,0u8];
        let b:u32 = mem::transmute(a);
        println!("{}",b);
    }
}