高级类型

类型别名

类型别名的作用:

  1. 减少重复
    (1) 例如如下的代码(trait 对象):
    Box<dyn Fn() + Send + 'static>
1
2
3
4
5
6
let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));

fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {

}
fn returns_long_type (f: Box<dyn Fn() + Send + 'static>) {}

修改为别名

1
2
type Trunk = Box<dyn Fn() + Send + 'static>;
let f: Trunk = Box::new(|| println!("hi"));

(2) 例子2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use std::io::Error;//标准库中是std::io::Error代表了所有可能的I/O错误
use std::fmt;
pub trait Write {
fn write(&mut self,buf :&[u8]) -> Result<usize,Error>;
fn flush(&mut self) -> Result<(),Error>;
fn write_all(&mut self,buf: &[u8]) -> Result<(),Error>;
fn write_fmt(&mut self,fmt: fmt::Arguments) -> Result<(),Error>;
}

type Result<T> = std::result::Result<T,std::io::Error>;//result<T,E>中的E放入了
//std::io::Error

//代码更新为:
pub trait Write {
fn write(&mut self,buf:&[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self,buf: &[u8]) -> Result<()>;
fn write_fmt(&mut self,fmt: Arguments) -> Result<()>;
}
  • 例子
1
2
3
4
5
6
7
8
9
type Kilometers = i32; //别名

fn main() {
let x : i32 = 5;
let y: Kilometers = 6;
let r: i32 = x + y;

println!("x + y = {}",r);
}

从不返回Never type

!是一种特殊类型,被称为empty type,因为没有值

这种又叫做never type,在函数不返回的时候充当返回值

1
2
3
fn bar() -> ! {
loop{}
}
  • 例子1
    猜谜游戏使用了这个参数,其中continue的值是never type
1
2
3
4
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,//!,会直接跳过,没有返回值
}

猜谜游戏解释链接😘

  • 例子2
1
2
3
4
5
6
7
8
9
//Option<T> 上的unwrap代码
impl<T> Option<T> {
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called 'option:;unwrap()'on a 'None' value"),//never type
}
}
}

动态大小类型和Sized trait

动态大小类型就是在运行过程中才能够知道大小的类型(dynamically sized types)DST
使用规则:

  1. 必须将动态大小类型的值置于某种指针之后,如Box\Rc

典型的(1)str

&str有两个值: str的地址和str的长度,大小在编译过程中可知,长度为2*usize

1
2
3
4
5
6
7
fn main() {
let s1 : &str = "Hello";
let s2 : &str = "world";
//不知道编译过程中的大小
// let s1: str = "Hello";
// let s2: str = "world";
}

通过特征名称引用的动态大小类型

为了使用trait对象,将其放入指针之后,如&trait 或者 Box

Sized trait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Rust使用Sized trait决定一个类型的大小是否在编译过程中可知
//trait为编译器在编译过程中实现大小

fn generic<T>(t: T) {//T是编译过程中知道大小的类型

}
//等价于
fn generic<T: Sized>(t: T) {//T为编译过程中知道大小的值

}

//为了放宽限制,使用:
fn generic<T: ?Sized>(t: &T) {//T可能是sized,也可能不是

}