Rust的高级类型

我爱海鲸 2024-03-13 18:37:44 rust学习

简介高级函数、闭包、newtype、类型别名

1、使用newtype模式实现类型安全和抽象

newtype模式可以:

-用来静态的保证各种值之间不会混淆并表明值的单位

-为类型的某些细节提供抽象能力

-通过轻量级的封装来隐藏内部实现细节

使用类型别名创建类型同义词

Rust提供了类型别名的功能:

为现有类型生产另外的名称(同义词)

并不是一个独立的类型

-使用type关键字

主要用途:减少代码字符重复

type Kilometers = i32;

fn main() {
    let x:i32 = 5;
    let y:Kilometers = 5;
    println!("x + y = {}",x + y);
}

我们来看另外一个例子:

type Thunk = Box<dyn Fn() + Send + 'static>;

fn takes_long_type(f:Thunk) {
    // --snip
}

fn returns_long_type()->Thunk {
    Box::new(||println!("hi"))
}

fn main() {
    let f :Thunk = Box::new(||println!("Hi"));
}

把一个比较长的类型使用类型别名进行替换,这样就可以尽可能的避免出错。

// use std::io::Error;
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> = Result<T,std::io::Error>;


type Result<T> = std::io::Result<T>;

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: fmt::Arguments)->Result<()>;
}

fn main() {
    
}

Never类型

有一个名为!的特殊类型:

   它没有任何值,行话称为空类型(empty type)
   我们倾向于叫它never类型,因为它在不返回的函数中充当返回类型

不返回值的函数也被称作发散函数(divergingfunction)

fn bar()->! {
    
}

fn main() {
    
}

上面的代码中我们期待返回的是!但是在我们的函数中什么也没有返回,什么都没返回就表示返回()类型,所以上面的代码会报错,那么!类型有什么用呢?

// impl<T> Option<T> {
//     pub fn unwrap(self) -> T {
//         match self {
//             Some(val) => val,
//             None => panic!("called `Option::unwrap()` on a `None` value"),
//         }
//     }
// }

fn main() {
    let guess = "";

    loop {
        let guess:u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };
    }

}

这里的continue表示返回的就是!(Nerver类型),整个表达式返回的就是u32的类型

上面注释的panic!返回的也是Nerver类型

fn main() {
    print!("forever ");


    loop {
        print!("and ever")
    }
}

上面代码中的loop它返回的也是一个Nerver类型,当然我们可以使用break进行跳出循环

动态大小和Sized Trait

Rust需要在编译时确定为--个特定类型的值分配多少空间。

动态大小的类型( Dynamically Sized Types,DST)的概念:

-编写代码时使用只有在运行时才能确定大小的值

str是动态大小的类型(注意不是&str) :只有运行时才能确定字符串的长度
-下列代码无法正常工作:
●lets1: str = "Hello there!";
●let s2: str = "How's it going?";

使用&str 来解决:
●str的地址
●str的长度

Rust使用动态大小类型的通用方式

附带一些额外的元数据来存储动态信息的大小.

-使用动态大小类型时总会把它的值放在某种指针后边

另外一种动态大小的类型: trait

每个trait都是--个动态大小的类型,可以通过名称对其进行引用

为了将trait用作trait对象,必须将它放置在某种指针之后

   例如&dyn Trait或Box<dyn Trait> (Rc<dyn Trait>)之后

Sized trait 

为了处理动态大小的类型,Rust 提供了-一个Sized trait来确定- - 个类型的大小在
编译时是否已知

编译时可计算出大小的类型会自动实现这--trait

Rust还会为每一个泛型函数隐式的添加Sized约束

// fn generic<T>(t:T) {
    
// }

// fn generic<T:Sized>(t:T) {
    
// }

fn main() {
    
}

上面注释的两行代码第一个函数会隐示的转换为第二个函数

默认情况下,泛型函数只能被用于编译时已经知道大小的类型,可以通过特殊语法
解除这- -限制

?Sized trait约束

// fn generic<T>(t:T) {
    
// }

// fn generic<T:Sized>(t:T) {
    
// }

// fn generic<T:?Sized>(t:&T) {
    
// }

fn main() {
    
}
?Sized表达了一种不确定性,它可能是Sized也可能不是Sized,这种语法只能使用来Sized这个Trait上面,T会变成引用,因为它可能不是Sized不确定大小,所以我们需要把它放到指针的后面
 
2、高级函数和闭包
 
函数指针
 
可以将函数传递给其它函数
函数在传递过程中会被强制转换成fn类型
fn类型就是“函数指针( function pointer)”
 
fn add_one(x:i32) -> i32 {
    x + 1
}

fn do_twice(f:fn(i32)->i32,arg:i32)->i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is:{}",answer);
}

函数指针与闭包的不同

fn是一个类型,不是一个trait

-可以直接指定fn为参数类型,不用声明一个以Fn trait 为约束的泛型参数

函数指针实现了全部3种闭包trait (Fn,FnMut,FnOnce) :

-总是可以把函数指针用作参数传递给--个接收闭包的函数

-所以,倾向于搭配闭包trait的泛型来编写函数:可以同时接收闭包和普通函数

某些情景,只想接收fn而不接收闭包:
-与外部不支持闭包的代码交互: C函数
fn main() {
    let list_of_numbers = vec![1,2,3];

    let list_of_strings:Vec<String> = list_of_numbers
    .iter()
    .map(|i|i.to_string())
    .collect();

    let list_of_numbers = vec![1,2,3];
    let list_of_strings:Vec<String> = list_of_strings
    .iter()
    .map(ToString::to_string)
    .collect();
}

上面的代码中我们能可以通过闭包来将i32类型的值转化为string也可以通过直接传递一个函数来进行转化

fn main() {
    enum Status {
        Value(u32),
        Stop,
    }

    let v = Status::Value(3);

    let list_of_statuses:Vec<Status> = 
    (0u32..20)
    .map(Status::Value)
    .collect();
}

返回闭包

闭包使用trait进行表达,无法在函数中直接返回一个闭包,可以将一一个实现了该
trait的具体类型作为返回值。

// fn returns_closure()->Fn(i32)->i32 {
//     |x|x + 1
// }

fn returns_closure()->Box<dyn Fn(i32)->i32> {
    Box::new(|x|x + 1)
}

fn main() {
    
}

 

 

 

你好:我的2025

上一篇:Rust的高级Trait

下一篇:Rust的宏