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. 线程创建,属性设置与获得,等待线程结束,线程中fork,以及执行exec()

    这篇博客的形式我想以分析代码不同情况为主: 点击(此处)折叠或打开 #include<stdio.h> #include<pthread.h> #include<time ...

  2. Jmeter 运行结果的csv文件生成报告

    把运行结果保存到本地,下次可以直接用结果生成测试报告. 一.首先保证脚本能正常运行 二.本地创建csv文件,用来保存运行结果 三.察看结果树,选择本地文件(上一步创建好的csv文件),保存运行结果,如 ...

  3. this.$set用法

    this.$set()的主要功能是解决改变数据时未驱动视图的改变的问题,也就是实际数据被改变了,但我们看到的页面并没有变化,这里主要讲this.$set()的用法,如果你遇到类似问题可以尝试下,vue ...

  4. linux下go环境配置

    环境申明: centos 7.4 1.go下载最新的版本(linux) 下载本地后rz到服务器,然后tar -zxvf  go1.9.2.linux-amd64.tar.gz   解压出go文件放在 ...

  5. Could not set property 'id' of 'class com.xxx.xxEntity'

    使用mybatisplus的save功能时,系统报错如下: Could not set property 'id' of 'class com.xxx.xxEntity' with value '13 ...

  6. 问题 B: 比大小

    题目描述 给你两个很大的数,你能不能判断出他们两个数的大小呢? 比如123456789123456789要大于-123456 输入 每组测试数据占一行,输入两个不超过1000位的10进制整数a,b 数 ...

  7. cmd 命令 导出导入oracle数据库 的 表

    原地址:https://www.cnblogs.com/mysterious-killer/p/11671741.html (防止) 导出: 不要数据的:exp username/pwd@localh ...

  8. 第一章 初始C语言

    第一章 初始C语言 目录 第一章 初始C语言 1. C语言起源 2. 选择C语言的理由 2.1 设计特性 2.2 高效性 2.3 可移植性 2.4 强大而灵活 2.5 面向程序员 3. C语言的应用范 ...

  9. [CSP-S2019] 树的重心

    也是一个很不错的题目. 考虑我们钦定重心为根. 那么就有这样一个性质: 如果我们断的边在一个点的子树里,则这个点不会成为断边后的分裂树的根. 所以我们就只要考虑断边在子树外即可. 那么我们设\(x\) ...

  10. Harbour.Space Scholarship Contest 2021-2022 题解

    多好的上分机会啊,要是换个时间(指改在 NOI 之后)我说不定就能上 2500 了(做白日梦 ing) A 签到题不多说,显然只有末尾为 \(9\) 的数是 interesting 的,因此答案就是 ...