Trait与生命周期

原文链接:(*´∇`*) 咦,又好了~ Rust – xiaocr_blogicon-default.png?t=N7T8http://www.xiaocr.fun/index.php/2024/03/18/trait%E4%B8%8E%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/

目录

Trait

定义trait

默认实现

trait作为参数

Trait Bound语法

通过+指定多个 trait bound

通过where简化 trait bound

返回实现了 trait 的类型

生命周期

生命周期避免了悬垂引用

函数中泛型生命周期

生命周期标记语法

函数签名中的生命周期标注

结构体定义中生命周期标注

生命周期省略

静态生命周期

结合泛型类型参数、trait bounds 和生命周期


😃Trait

trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共享的行为


注意:trait 类似于其他语言中常被称为 接口interfaces)的功能,虽然有一些不同。

❗️定义trait

一个类型的行为由其可供调用的方法构成。如果可以对不同类型调用相同的方法的话,这些类型就可以共享相同的行为了。trait 定义是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所必需的行为的集合。

pub trait Summary {
    fn summarize(&self) -> String;
}

这里使用 trait 关键字来声明一个 trait,后面是 trait 的名字,在这个例子中是 Summary。在大括号中声明描述实现这个 trait 的类型所需要的行为的方法签名,在这个例子中是 fn summarize(&self) -> String。

默认实现


fn main() {
pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}
}

trait作为参数

使用 trait 来接受多种不同类型的参数

pub fn notify(item: impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

对于 item 参数,我们指定了 impl 关键字和 trait 名称,而不是具体的类型。该参数支持任何实现了指定 trait 的类型。在 notify 函数体中,可以调用任何来自 Summary trait 的方法,比如 summarize。我们可以传递任何 NewsArticle 或 Tweet 的实例来调用 notify。任何用其它如 String 或 i32 的类型调用该函数的代码都不能编译,因为它们没有实现 Summary。

Trait Bound语法

impl Trait 语法适用于直观的例子,它实际上是一种较长形式语法的语法糖。我们称为 trait bound,它看起来像:

pub fn notify<T: Summary>(item: T) {
    println!("Breaking news! {}", item.summarize());
}

通过+指定多个 trait bound

如果 notify 需要显示 item 的格式化形式,同时也要使用 summarize 方法,那么 item 就需要同时实现两个不同的 trait:Display 和 Summary。这可以通过 + 语法实现:

pub fn notify(item: impl Summary + Display) {

+ 语法也适用于泛型的 trait bound:

pub fn notify<T: Summary + Display>(item: T) {

通过指定这两个 trait bound,notify 的函数体可以调用 summarize 并使用 {} 来格式化 item。

通过where简化 trait bound

每个泛型有其自己的 trait bound,所以有多个泛型参数的函数在名称和参数列表之间会有很长的 trait bound 信息,这使得函数签名难以阅读。为此,Rust 有另一个在函数签名之后的 where 从句中指定 trait bound 的语法

fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone,
          U: Clone + Debug
{

返回实现了 trait 的类型

也可以在返回值中使用 impl Trait 语法,来返回实现了某个 trait 的类型:

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,
    }
}

生命周期

生命周期的概念从某种程度上说不同于其他语言中类似的工具,毫无疑问这是 Rust 最与众不同的功能。

生命周期避免了悬垂引用

生命周期的主要目标是避免悬垂引用,它会导致程序引用了非预期引用的数据

{
    let r;

    {
        let x = 5;
        r = &x;
    }

    println!("r: {}", r);
}

会出现错误,:“x dose not live long enough

函数中泛型生命周期

下面这个代码是会报错的

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

因为 Rust 并不知道将要返回的引用是指向 x 或 y。事实上我们也不知道,因为函数体中 if 块返回一个 x 的引用而 else 块返回一个 y 的引用!

当我们定义这个函数的时候,并不知道传递给函数的具体值,所以也不知道到底是 if 还是 else 会被执行。我们也不知道传入的引用的具体生命周期

77c47f15aef222b134cb6484a0a7a6b9.png

生命周期标记语法

生命周期标注并不改变任何引用的生命周期的长短。与当函数签名中指定了泛型类型参数后就可以接受任何类型一样,当指定了泛型生命周期后函数也能接受任何生命周期的引用。生命周期标注描述了多个引用生命周期相互的关系,而不影响其生命周期。

&i32        // 引用
&'a i32     // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用

函数签名中的生命周期标注

就像泛型类型参数,泛型生命周期参数需要声明在函数名和参数列表间的尖括号中

fn longest <'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

结构体定义中生命周期标注

需要为结构体定义中的每一个引用添加生命周期标注

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.')
        .next()
        .expect("Could not find a '.'");
    let i = ImportantExcerpt { part: first_sentence };
}

生命周期省略

在编写了很多 Rust 代码后,Rust 团队发现在特定情况下 Rust 开发者们总是重复地编写一模一样的生命周期标注。这些场景是可预测的并且遵循几个明确的模式。生命周期省略规则lifetime elision rules)

  • 第一条规则是每一个是引用的参数都有它自己的生命周期参数。换句话说就是,有一个引用参数的函数有一个生命周期参数:fn foo<'a>(x: &'a i32),有两个引用参数的函数有两个不同的生命周期参数,fn foo<'a, 'b>(x: &'a i32, y: &'b i32),依此类推。
  • 第二条规则是如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数:fn foo<'a>(x: &'a i32) -> &'a i32。
  • 第三条规则是如果方法有多个输入生命周期参数并且其中一个参数是 &self 或 &mut self,说明是个对象的方法(method)

静态生命周期

'static,其生命周期能够存活于整个程序期间。所有的字符串字面量都拥有 'static 生命周期

fn main() {
let s: &'static str = "I have a static lifetime.";
}

结合泛型类型参数、trait bounds 和生命周期

fn main() {
use std::fmt::Display;

fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
    where T: Display
{
    println!("Announcement! {}", ann);
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/468335.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】内存管理和模板基础(new、delete、类及函数模板)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 内存分布 C内存管理方式 new/delete操作内置类型 new和delete操作自定义类型 operator new与operator d…

Cesium:绘制一个 3DTiles 对象的外包盒顶点

作者:CSDN @ _乐多_ 本文将介绍如何使用 Cesium 引擎根据模型的中心坐标,半轴信息,绘制一个 3DTiles 对象的外包盒顶点。 外包盒是一个定向包围盒(Oriented Bounding Box),它由一个中心点(center)和一个包含半轴(halfAxes)组成。半轴由一个3x3的矩阵表示,这个矩阵…

Apache Dolphinscheduler - 无需重启 Master-Server 停止疯狂刷日志解决方案

记录的是一个 3.0 比较难搞的问题&#xff0c;相信不少使用过 3.0 的用户都遇到过 Master 服务中存在一些工作流或者任务流一直不停的死循环的问题&#xff0c;导致疯狂刷日志。不过本人到现在也没找到最关键的触发原因&#xff0c;只是看到一些连锁反应带来的结果…… 影响因素…

qmldir的理解

目录结构&#xff1a; 文件内容 qmldir中&#xff1a; module QtLocaion plugin declarative_location classname QtLocationDeclarativeModule typeinfo plugins.qmltypes 其中&#xff1a; QtLocaion必须与qmldir所在的文件夹名字一样 plugin 后面的declarative_location 为…

SHELL——条件判断语句练习

目录 一、练习题目 二、解答过程 1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查次磁盘剩余空间。 安装邮件服务 配置邮件服务 编写脚本work1.sh 添加计划任务 2、判断web服务是否运行&#xff1a;…

项目中遇到的sql问题记录

有一张表&#xff0c;表结构及数据如下&#xff1a; INSERT INTO test.test_approve(approve_no, tra_date, tablename, part_dt) VALUES (approve001, 2021-02-18 00:00:00, tableA, 2024-03-18); INSERT INTO test.test_approve(approve_no, tra_date, tablename, part_dt) …

【Linux】日常使用命令(三)

文章目录 **cal 命令****date 命令****bc 命令****Linux下玩小游戏**&#xff1a; cal 命令 功能描述: cal 命令用于显示日历。 常用选项: -3&#xff1a;显示前一个月、当前月和下一个月的日历。-y&#xff1a;显示整年的日历。 常用示例: # 示例 1: 显示当前月的日历 cal# …

Easy Connect下载(Windows版)

文章目录 1. 下载连接2. 安装 1. 下载连接 百度网盘链接&#xff1a;https://pan.baidu.com/s/13r4wxz-Df3S_IMruZIDucw  提取码&#xff1a;mmcc 2. 安装 1. 下载安装包解压后&#xff0c;双击.exe文件就可以安装软件。 2. 耐心等待&#xfeff;&#xfeff;Easy Connect安装…

Android 开发环境搭建(Android Studio 安装图文详细教程)

Android Studio 下载 https://developer.android.google.cn/studio?hlzh-cn Android Studio 安装 检查电脑是否启用虚拟化 如果没有开启虚拟化&#xff0c;则需要进入电脑的 BIOS 中开启 直接 next选择安装的组件&#xff0c;Android Studio 和 Android 虚拟设备&#xff…

Gitlab-runner注册与配置

文章目录 概要操作流程获取HTTPS证书上传证书修改gitlab-runner dns配置文件gitlab-runner 注册 概要 本文主要介绍了Gitlab-runner在内网环境注册到gitlab的操作方式。内网环境如下&#xff1a; 1、gitlab-runner由docker镜像部署&#xff1b; 2、gitlab部署与内网&#xff0…

Linux的背景介绍

1.Linux的发展史 Linux&#xff0c;一般指GNU/Linux&#xff08;单独的Linux内核并不可直接使用&#xff0c;一般搭配GNU套件&#xff0c;故得此称呼&#xff09;&#xff0c;是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08…

Android studio开发中Virtual Device模拟器的设置和屏幕错位等问题

Android SDK开发中Virtual Device模拟器的设置和使用 本文介绍android studio2023 3.1.13版本中模拟器的设置和在cordova开发中的运行方法 对于老版android studioAVD模拟器的使用&#xff0c;参见&#xff1a;Android SDK手机应用开发中第三方模拟器、真机运行方法以及AVD模拟…

安卓RecyclerView简单用法

废话不多说上代码 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schem…

60+款VSCode插件,构建超舒适开发环境

本文不做任何编辑器的比较&#xff0c;只是我本人日常使用 vscode 进行开发&#xff0c;并且比较喜欢折腾 vscode &#xff0c;会到处找这一些好玩的插件&#xff0c;于是越攒越多&#xff0c;今天给大家推荐一下我收藏的 60 多个 vscode 插件&#xff0c;据说插件装太多&#…

qt+ffmpeg 实现音视频播放(二)之音频播放

一、音频播放流程 1、打开音频文件 通过 avformat_open_input() 打开媒体文件并分配和初始化 AVFormatContext 结构体。 函数原型如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); 参数说…

Python统计初步

文章目录 基本统计特征区间统计PandaspandasGUI Python科学计算&#xff1a;数组&#x1f4af;数据生成&#x1f4af;数据交互&#x1f4af;微积分&#x1f4af;插值&#x1f4af;拟合&#x1f4af;FFT&#x1f4af;卷积&#x1f4af;滤波 基本统计特征 分析统计特征是数据分…

大规模采集主流电商平台商品详情页获取商品详情,SKU,价格操作流程

taobao API 接入 淘宝接口解析是指通过淘宝提供的API&#xff08;Application Programming Interface&#xff09;来实现程序与淘宝平台的数据交互和功能调用。通过淘宝接口&#xff0c;用户可以实现商品信息获取、订单管理、物流跟踪等功能。 在使用淘宝接口前&#xff0c;首…

BUUCTF-MISC-[QCTF2018]picture

题目链接&#xff1a;BUUCTF在线评测 (buuoj.cn) 解题过程 下载附件发现没有扩展名&#xff0c;用010Editor打开是png图片 保存为png格式打开&#xff1a; BUUCTF平台会缺失一些提示&#xff0c;点开题目链接在GitHub里有题目描述&#xff1a; 提示判断应该是lsb隐写&#xff0…

Javaweb的学习21_CSS_属性

CSS的属性 (常用)属性&#xff1a; 1. 字体、文本 font-size&#xff1a;字体大小 color&#xff1a;文本颜色 text-align&#xff1a;文本的对齐方式 line-height&#xff1a;行高 2. 背景 background&#xff1a;是个复合属性 3. 边框 border&#xff1a;设置边框&#xff0c…

robots协议详解:爬虫也要有边界感

随着互联网的迅猛发展,信息的获取变得越来越便捷,而网络爬虫(Spider)技术就是其中之一。网络爬虫是一种自动化程序,它能够遍历互联网上的网页,提取信息,用于各种用途,例如搜索引擎索引、数据挖掘、价格比较等。但是,爬虫技术虽然强大,但是也是一把双刃剑,在正当使用…