Rust 泛型

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。在Rust中编译时编译器会将泛型代码具化为不同具体类型的多份代码,所以泛型代码只是提供了一种通用代码的抽象,并不能减少编译后真正生成的代码量。

泛型创建

泛型函数

fn give_me<T>(value:T){
let _=value;
}

泛型函数的创建需要在方法名和圆括号间放置泛型参数,之后就可以将该泛型参数视为类型使用。

使用

fn main() {
let a="generics";
let b=1024;
give_me(a);
give_me(b);
}

泛型类型

泛型类型的创建需要在类型名和{}间放置泛型参数,之后就可以将该泛型参数视为类型使用。

结构体:

struct GenericStruct<T>(T);
struct Container<T>{
item:T,
}

使用:

let i=GenericStruct(1);
let s=GenericStruct(String::from("1111"));
let ic=Container{item:1};
let is=Container{item:String::from("is")};

枚举:

enum Transmission <T>{
Singal(T),
NoSingal,
}

使用:

let ei=Transmission::Singal(1);
let es=Transmission::Singal(String::from("222"));
let eni=Transmission::<i32>::NoSingal;
let ens:Transmission<String>=Transmission::NoSingal;

注意:使用泛型ZST枚举实例要使用::<>(turbofish)来指明泛型参数是哪种类型。

泛型实现:

泛型实现要在impl后声明泛型参数,然后就可以把泛型参数当作具体类型使用。

拿上一部分的Container为例,为其实现方法:

impl<T> Container<T> {
fn new(item:T)->Self{
Container{item}
}
}

使用:

let container_i32=Container::new(1);
let container_str=Container::new(String::from("111"));

还可以为具体类型参数提供实现:

impl Container<i32>{
// fn new(item:i32)->Self{
// Container{item}
// }
fn toString(&self)->String{
self.item.to_string()
}
}

这种具体类型参数的实现只对此类型可用,并且不能和泛型实现函数名冲突。

特征区间(trait bounds)

上述所有示例程序,我们都只是简单的提供了一个占位符来表示类型,编译器并不知道具体的类型信息,所以我们除了用它们来表示类型外,并不能对这些占位符或者它们表示的变量调用方法,好在Rust提供了trait bounds来告知编译器相关的类型信息来完成这项工作。

我们可以在泛型声明处使用“:”来对类型占位符进行一些约束来告知编译器相关的类型信息。一些例子如下:

在方法上使用trait bounds:
trait Person{
fn sleep(){
println!("person need sleep");
}
fn get_name(&self)->&str;
}
struct Student{name:String}
impl Person for Student {
fn get_name(&self)->&str{
&self.name
}
} fn who<T:Person>(anyone:&T){
println!("I'm {}",anyone.get_name());
}
fn doing_at_night<T:Person>(anyone:&T){
T::sleep();
}

使用:

 let stu=Student{name:"YSS".to_string()};
Student::who(&stu);
Student::doing_at_night(&stu);

需要注意的是,trait bounds提供了对泛型参数的约束导致对传入的泛型类型有了一定的要求,只有符合泛型约束的类型才能正确使用泛型代码。

trait bounds除了可以像上述那样指定以外,还可以把泛型约束单独提出来放置到返回值之后{}之前的where语句中(多个泛型参数","分割),这在约束较长或者泛型参数较多的情况下能够提高代码可读性。

上述例子可改写如下:

fn who<T>(anyone: &T)
where
T: Person,
{
println!("I'm {}", anyone.get_name());
}
fn doing_at_night<T>(anyone: &T)
where
T: Person,
{
T::sleep();
}
类型上的trait bounds:
struct Foo<T:Display>{
bar:T
}

struct Foo<T> where T:Display{
bar:T
}

这样约束后,实例化结构体Foo时,bar只能是实现了Display trait的实例。

泛型实现上的trait bounds:
trait Eatable{
fn eat(&self);
}
#[derive(Debug)]
struct Food<T>(T);
impl<T:Debug> Eatable for Food<T>{
fn eat(&self) {
println!("Eating{:?}",self);
}
}

impl<T> Eatable for Food<T>where T:Debug{
fn eat(&self) {
println!("Eating{:?}",self);
}
}

特征区间组合

我们还可以使用“+”为泛型指定多个特征区间,例如:

trait Eat{
fn eat(&self){
println!("eat");
}
}
trait Code{
fn code(&self){
println!("code");
}
}
trait Sleep{
fn sleep(&self){
println!("sleep");
}
}
fn coder_life <T:Eat+Code+Sleep> (coder:T){
coder.eat();
coder.code();
coder.sleep();
}

impl特征区间

对于涉及到堆分配或无法用具体类型表示约束的类型(例如闭包),我们可以使用impl来指定特征区间:

fn lazy_adder(a:u32,b:u32)->impl Fn()->u32{
move||a+b
}

如果用普通trait bounds的话,编译器会报如下错误:

fn lazy_adder<T:Fn()->u32>(a:u32,b:u32)->T{
move||a+b
}
error[E0308]: mismatched types
--> src/main.rs:106:5
|
105 | fn lazy_adder<T:Fn()->u32>(a:u32,b:u32)->T{
| - this type parameter - expected `T` because of return type
106 | move||a+b
| ^^^^^^^^^ expected type parameter `T`, found closure
|
= note: expected type parameter `T`
found closure `[closure@src/main.rs:106:5: 106:14]`
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `T`

因为闭包是堆分配的,如果返回类型不做特殊处理的话,是在栈上的变量,不会像智能指针那样指向堆分配内容,所以我们只能用impl或者用智能指针包裹,像下面这样:

fn lazy_adder(a:u32,b:u32)->Box<Fn()->u32>{
Box::from(move||a+b)
}

对返回闭包感兴趣的老哥可以看看这个帖子:

https://medium.com/journey-to-rust/closures-part-2-29536393dd92

Rust 泛型的更多相关文章

  1. Atitit.rust语言特性 attilax 总结

    Atitit.rust语言特性 attilax 总结 1. 创建这个新语言的目的是为了解决一个顽疾:软件的演进速度大大低于硬件的演进,软件在语言级别上无法真正利用多核计算带来的性能提升.1 2. 不会 ...

  2. the rust book 的简单入门笔记

    rust learning day 1 (2021/05/27) 学了常量,变量,数据类型,控制流,所有权 char 的宽度是4字节,一个 unicode 的宽度 控制流条件都不要括号 rust 中的 ...

  3. Rust语言开发

    Rust开发 第一个程序 fn main() { println!("Hello, world!"); // 带!号的都是宏 并不是函数 } fn main() { let nam ...

  4. Rust生命周期bound用于泛型的引用

    在实际编程中,可能会出现泛型引用这种情况,我们会编写如下的代码: struct Inner<'a, T> { data: &'a T, } 会产生编译错误: error[E0309 ...

  5. Rust中的泛型

    go没有的,rust有呢~~ fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = li ...

  6. Rust语言的多线程编程

    我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...

  7. Rust语言:安全地并发

    http://www.csdn.net/article/2014-02-26/2818556-Rust http://www.zhihu.com/question/20032903 Rust是近两年M ...

  8. D、GO、Rust 谁会在未来取代 C?为什么?——Go语言的定位非常好,Rust语言非常优秀,D语言也不错

    不要管我的地位和 D 语言创造者之一的身份.我会坦诚的回答这个问题.我熟悉 Go 和 Rust,并且知道 D 的缺点在哪里.我鼓励人们在 Rust 和 Go 社区相似身份的人,也可以提出他们诚恳的观点 ...

  9. Rust语言

    Rust语言 https://doc.rust-lang.org/stable/book/ http://www.phperz.com/article/15/0717/141560.html Rust ...

随机推荐

  1. ELK7.11.2版本安装部署及ElastAlert告警相关配置

    文档开篇,我还是要说一遍,虽然我在文档内容中也会说好多遍,但是希望大家不要嫌我墨迹: 请多看官方文档,请多看命令行报错信息,请多看日志信息,很多时候它们比百度.比必应.比谷歌有用: 请不要嫌麻烦,打开 ...

  2. Dynamics CRM安装教程一:域环境准备

    服务器环境:Windows Service 2016 Stand Windows域是计算机网络的一种形式,其中所有用户账户,计算机,打印机和其他安全主体都在位于称为域控制器的一个或多个中央计算机集群上 ...

  3. BUAA_OO_第二单元

    BUAA_OO_2020_UNIT2 一.程序结构分析 第五次作业 UML & Mertrics ​ 电梯的调度问题,实质上就是任务的请求与分配问题,笔者在第五次作业中采用简单的"生 ...

  4. 面试官:Java中线程是按什么顺序执行的?

    摘要:Java中多线程并发的执行顺序历来是面试中的重点,掌握Java中线程的执行顺序不仅能够在面试中让你脱颖而出,更能够让你在平时的工作中,迅速定位由于多线程并发问题导致的"诡异" ...

  5. 2.EL表达式&JSTL标签库常用方法

    1.EL表达式 Expression Language表达式语言,主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出. 格式为${表达式} EL表达式输出Bean的普通属性.数组属性.Li ...

  6. 嗝,我饱了——IDEA食用指南

    1 概述 IDEA全称IntelliJ IDEA,主要用于Java开发的IDE,代码自动提示,重构,JUnit,代码分析等的功能非常牛逼,这篇文章首先介绍目前为止IDEA最新版本的特性,然后从UI,常 ...

  7. JAVAEE_Servlet_17_关于乱码问题

    关于乱码问题 * 数据传递过程中的乱码 解释:数据传递过程中的乱码是指: 将数据从浏览器发送给服务器的时候,服务器接收到的数据是乱码的. - ISO-8859-1 是国际标准码,不支持中文编码,它兼容 ...

  8. xPath,beautifulsoup和pyquery

    一.XPath from lxml import etree html = etree.parse('html源代码',etree.HTMLPaser()) 1.节点的获取 a.html.xpath( ...

  9. 【ElasticSearch】shards,replica,index之间的关系

    1.index 包含多个shard ,在创建index的时候可以自定义shards和replica的数量 例如: 新增一个index,手动指定shard和replica的数量 PUT demo_ind ...

  10. 针对中国政府机构的准APT攻击样本Power Shell的ShellCode分析

    本文链接网址:http://blog.csdn.net/qq1084283172/article/details/45690529 一.事件回放 网络管理员在服务器上通过网络监控软件检测到,有程序在不 ...