Every programming language has tools for effectively handling the duplication of concepts. In Rust, one such tool is generics. Generics are abstract stand-ins for concrete types or other properties.

泛型的作用:降低代码冗余

  1. Identify duplicate code.
  2. Extract the duplicate code into the body of the function and specify the inputs and return values of that code in the function signature.
  3. Update the two instances of duplicated code to call the function instead.

Traits: Defining Shared Behavior

trait tells the Rust compiler about functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can use trait bounds to specify that a generic can be any type that has certain behavior.

Note: Traits are similar to a feature often called interfaces in other languages, although with some differences.

#![allow(unused)]

pub trait Person {
fn food(&self) -> String; fn eat(&self) -> String {
format!("(eat {}...)", self.food())
}
} pub struct Teacher {
pub name: String,
} impl Person for Teacher {
fn food(&self) -> String {
format!("{}", "面包")
}
} pub struct Student {
pub username: String,
pub age: i8,
} impl Person for Student {
fn food(&self) -> String {
format!("{}", "水果")
}
} pub fn test(){
let tch = Teacher {
name: String::from("a01"),
}; println!("teacher: {}", tch.eat()); let st = Student {
username: String::from("Penguins win the Stanley Cup Championship!"),
age: 12,
}; println!("student: {}", st.eat());
}
mod tra;

fn main() {
println!("----------------");
tra::tra1::test();
}

输出


----------------
teacher: (eat 面包...)
student: (eat 水果...)

 

Traits as Parameters

Now that you know how to define and implement traits, we can explore how to use traits to define functions that accept many different types.

pub fn notify_eat(item: &impl Person) {
println!("notify: {}", item.eat());
} pub fn test2(){
let tch = Teacher {
name: String::from("a01"),
}; notify_eat(&tch); let st = Student {
username: String::from("Penguins win the Stanley Cup Championship!"),
age: 12,
}; notify_eat(&st);
}
----------------
notify: (eat 面包...)
notify: (eat 水果...)

Trait Bound Syntax

pub fn notify<T: Person>(item: &T) {
println!("notify: {}", item.eat());
} pub fn test3(){
let tch = Teacher {
name: String::from("a01"),
}; notify(&tch); let st = Student {
username: String::from("hong yun"),
age: 12,
}; notify(&st);
}
----------------
notify: (eat 面包...)
notify: (eat 水果...)

Returning Types that Implement Traits

pub trait Summary {
fn summarize(&self) -> String;
} pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
} impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
} pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
} impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
} fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
retweet: false,
}
}

泛型的复制与比较

#![allow(unused)]

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0]; for &item in list {
if item > largest {
largest = item;
}
} largest
} pub fn test() {
let number_list = vec![34, 50, 25, 100, 65]; let result = largest(&number_list);
println!("The largest number is {}", result); let char_list = vec!['y', 'm', 'a', 'q']; let result = largest(&char_list);
println!("The largest char is {}", result);
}

If we don’t want to restrict the largest function to the types that implement the Copy trait, we could specify that T has the trait bound Clone instead of Copy. Then we could clone each value in the slice when we want the largest function to have ownership. Using the clone function means we’re potentially making more heap allocations in the case of types that own heap data like String, and heap allocations can be slow if we’re working with large amounts of data.

Validating References with Lifetimes

说生命周期就绕不开rust的引用与借用,可先阅读一遍下面的文章,回顾一下引用与借用的概念,再继续阅读本文章

2.5 References & Borrowing

One detail we didn’t discuss in the “References and Borrowing” section in Chapter 4 is that every reference in Rust has a lifetime, which is the scope for which that reference is valid. Most of the time, lifetimes are implicit and inferred, just like most of the time, types are inferred. We must annotate types when multiple types are possible. In a similar way, we must annotate lifetimes when the lifetimes of references could be related in a few different ways. Rust requires us to annotate the relationships using generic lifetime parameters to ensure the actual references used at runtime will definitely be valid.

Preventing Dangling References with Lifetimes

fn main() {
{
let r; {
let x = 5;
r = &x;
} println!("r: {}", r);
}
}

Note: The examples declare variables without giving them an initial value, so the variable name exists in the outer scope. At first glance, this might appear to be in conflict with Rust’s having no null values. However, if we try to use a variable before giving it a value, we’ll get a compile-time error, which shows that Rust indeed does not allow null values.

The outer scope declares a variable named r with no initial value, and the inner scope declares a variable named x with the initial value of 5. Inside the inner scope, we attempt to set the value of r as a reference to x. Then the inner scope ends, and we attempt to print the value in r. This code won’t compile because the value r is referring to has gone out of scope before we try to use it. Here is the error message:

$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0597]: `x` does not live long enough
--> src/main.rs:7:17
|
7 | r = &x;
| ^^ borrowed value does not live long enough
8 | }
| - `x` dropped here while still borrowed
9 |
10 | println!("r: {}", r);
| - borrow later used here error: aborting due to previous error For more information about this error, try `rustc --explain E0597`.
error: could not compile `chapter10`. To learn more, run the command again with --verbose.

The variable x doesn’t “live long enough.” The reason is that x will be out of scope when the inner scope ends on line 7. But r is still valid for the outer scope; because its scope is larger, we say that it “lives longer.” If Rust allowed this code to work, r would be referencing memory that was deallocated when x went out of scope, and anything we tried to do with r wouldn’t work correctly. So how does Rust determine that this code is invalid? It uses a borrow checker.

3.5 Rust Generic Types, Traits, and Lifetimes的更多相关文章

  1. Effective Java 26 Favor generic types

    Use generic types to replace the object declaration Add one or more type parameters to its declarati ...

  2. Rust 总章

    1.1 Rust安装 3.5 Rust Generic Types, Traits, and Lifetimes 3.6 String 与 切片&str的区别 https://openslr. ...

  3. Effective Java 23 Don't use raw types in new code

    Generic types advantage Parameterized type can provide erroneous check in compile time. // Parameter ...

  4. Effective Java 27 Favor generic methods

    Static utility methods are particularly good candidates for generification. The type parameter list, ...

  5. C# Generic(转载)

    型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具体 ...

  6. castle windsor学习----- Referencing types in XML 在xm文件中引用类型

    当从xml引用installer的语法如下 <install type="Acme.Crm.Infrastructure.ServicesInstaller, Acme.Crm.Inf ...

  7. 06 Frequently Asked Questions (FAQ) 常见问题解答 (常见问题)

    Frequently Asked Questions (FAQ) Origins 起源 What is the purpose of the project? What is the history ...

  8. CGAL Manual/tutorial_hello_world.html

    Hello World Author CGAL Editorial Board 本教程是为知道C++和几何算法的基本知识的CGAL新手准备的.第一节展示了如何特化点和段CGAL类,以及如何应用几何谓词 ...

  9. Java 8 Features – The ULTIMATE Guide--reference

    Now, it is time to gather all the major Java 8 features under one reference post for your reading pl ...

随机推荐

  1. 超过1W字深度剖析JVM常量池(全网最详细最有深度)

    面试题:String a = "ab"; String b = "a" + "b"; a == b 是否相等 面试考察点 考察目的: 考察对 ...

  2. 2016西邮Linux兴趣小组大事记

    2016年还有半个小时就结束了,前面把自己9月做的规划拿出来完善了下,觉得真的是不容易的一年,所有的事情只有自己经历过才会有不一样的感受,世上无难事,只怕有心人. 这是我九月份制定的计划: 下面是20 ...

  3. 重装系统——联想window 10

    大四了,读了四年大学,唉,混的,啥也不会,工作也找不到,真的不知道这大学四年到底干了什么.专业是计算机方向的,但居然,不敢,也不会装电脑系统,大学四年的文件都是乱放的,更那个的是,有些软件卸载不完全, ...

  4. loadRunner12 设置关联 获取服务端动态数据

    关联:服务器返回给客户端一些动态变化的值,客户端用这些值去访问服务器,不能把这些值写死在脚本里面,而应该存放在一个变量里面. 在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关 ...

  5. 03 | 变量的解构赋值 | es6

    变量的解构赋值 数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前,为变量赋值,只能直接指定值. let a ...

  6. C# | VS2019连接MySQL的三种方法以及使用MySQL数据库教程

    本文将介绍3种添加MySQL引用的方法,以及连接MySQL和使用MySQL的教程 前篇:Visual Studio 2019连接MySQL数据库详细教程 \[QAQ \] 第一种方法 下载 Mysql ...

  7. Go语言核心36讲(Go语言实战与应用三)--学习笔记

    25 | 更多的测试手法 在本篇文章,我会继续为你讲解更多更高级的测试方法.这会涉及testing包中更多的 API.go test命令支持的,更多标记更加复杂的测试结果,以及测试覆盖度分析等等. 前 ...

  8. Spring的轻量级实现

    作者: Grey 原文地址:Spring的轻量级实现 本文是参考公众号:码农翻身 的从零开始造Spring 教程的学习笔记 源码 github 开发方法 使用TDD的开发方法,TDD的开发流程是: 写 ...

  9. vue如何写组件(script标签引入的方式)

    很多人知道.vue结构的单文件组件形式,不过这种单文件组件的结构如果要加入到现有的jquery项目中就比较麻烦了,那如果我们又想用vue来写模板,又不想引入vue-cli管理,那该怎么来写组件呢?别着 ...

  10. IDEA maven Run Maven 启动方式

    首先想要使用 Run Maven 启动需要在IDEA设置里找到plugins  在plugins窗口下面找到Browse Repositories   打开Browse Repositories 下载 ...