再谈类型

我们已经学习过了几乎所有RUST关于类型的定义,本节将针对类型的其他注意点以及使用方法 做更近一步阐述

类型别名

并非RUST有类型别名,甚至C里面都有类型别名typedef 相比较C语言,RUST类型别名更具有泛型的特点

应用场景1,类型别名可以缩短代码

struct ParsePayLoad<T> {
    inner: T
}

struct ParseError<E> {
    inner: E 
}

fn parse_payload<T,E> (stream: &[u8])-> Result<ParsePayLoad<T>,ParseError<E>> {
    unimplemented!();
} 

我们可以看到,上面的代码parse_payload 函数签名已经很长了,这时候可以使用类型别名

type ParseResult<T,E> = Result<ParsePayLoad<T>,ParseError<E>>;

fn parse_payload<T,E> (stream: &[u8])-> ParseResult<T,E> {
    unimplemented!();
} 

标准库中也大量使用了类似的方法,比如File模块的 关于Result重定义

不定长类型

我们前面介绍过的类型,几乎都是定长类型(类型的大小是确定的),RUST中也有两种不定长的类型

  • [T] : 切片类型,切片类型代表一个内存的不可变视图

Screenshot

  • dyn Trait: 特征对象类型

上述两种类型都无法直接使用(不定长类型变量内存大小无法确定) 因此只能通过他们的引用使用

  • 任何把不定长类型作为最后一个字段的结构体 也被视为不定长类型

对于不定长类型 我们只能以引用的方式使用,引用包含了指向内存的地址,以及内存的长度

Sized&?Sized

Sized 特征是一个标记特征,标识某个类型是内存大小确定的,对于不定长类型,需要通过?Sized 标记,显示告诉编译器,该类型不对大小 已知做限制,RUST 会为所有类型默认添加Sized约束

联合

联合是C里面的类型,RUST为了和C语言交互,也支持了union类型 该类型直接映射C语言的实现

union Metric {
    rounded: u32,
    precise: f32,
}

fn main(){
    let mut a = Metric {rounded: 323};

    unsafe {
        println!("{}",a.rounded);
        println!("{}",a.precise);
    }
    a.precise = 33.3;

    unsafe {
        println!("{}",a.rounded);
        println!("{}",a.precise);
    }
}

全局值

我们已经讲过 在程序中有三个内存地址的变量: 栈、堆、BSS段,前两个我们已经见过了,今天看第三个数据区的变量

常量: 常量的值在内存中是不可变的,语法为 const NAME(大写) : T = value 常量在任何时候使用 都是以内联形式使用

静态值: 静态值对应C里面的 全局变量,既然是变量 那就可以修改

static mut BAZ: u32 = 4;
static FOO: u8  =122;


fn main(){
    unsafe {
        println!("baz is {}",BAZ);
        BAZ= 100;
    }
}

类型转换

强制类型转换是一种将类型 降级或者升级到其他类型的机制。 当类型转换隐式发生时,被称为强制类型转换。RUST 还允许各种级别的 类型转换,要执行简单的类型转换,我们使用关键字as

let a = 34u8;
let b = a as u64;

除了简单的基元类型,也可以把某些实现了特征的类型,转为特征对象

use std::fmt::Display;

fn show_me(item: &dyn Display) {
    println!("{}",item);
}

fn main() {
    let a = "abc";
    show_me(&a);
    let c = &a as &dyn Display;
}

另外还有可以从引用转为原始指针,我们之前已经见识过了

除了使用as进行隐式的类型转换,还有一种更加安全和通用的方法 通过 from/into 特征

pub trait From<T>: Sized {
    // Required method
    fn from(value: T) -> Self;
}
pub trait Into<T>: Sized {
    // Required method
    fn into(self) -> T;
}

一个示例

#[derive(Debug)]
struct Apple(i32);

impl From<i32> for Apple {
    fn from(value: i32) -> Self {
        Apple(value)
    }
}

impl Into<i32> for Apple {
    // Required method
    fn into(self) -> i32 {
        self.0
    }
}

fn main() {
    let apple = Apple::from(10);
    println!("{:?}", apple);

    let size: i32 = apple.into();
    println!("{}", size);
}