Rust 学习笔记:生命周期
Rust 学习笔记:生命周期
- Rust 学习笔记:生命周期
- 使用生命周期防止悬空引用
- 借用检查器
- 函数中的泛型生命周期
- 生命周期注释语法
- 函数签名中的生命周期注解
- 从生命周期的角度思考
- 结构定义中的生命周期注解
- 省略生命周期
- 方法定义中的生命周期注释
- 静态生命周期
- 泛型类型参数、trait 约束和生命周期
Rust 学习笔记:生命周期
生命周期是我们已经使用过的另一种泛型。
生命周期不是确保类型具有我们想要的行为,而是确保引用在我们需要时有效。
Rust 中的每个引用都有生命周期,也就是引用有效的范围(作用域)。
大多数时候,生命周期是隐式的和推断的,就像大多数时候,类型是推断的一样。只有当可能有多个类型时,我们才需要注释类型。
以类似的方式,当引用的生命周期可能以几种不同的方式相关联时,我们必须注释生命周期。Rust 要求我们使用泛型生命周期参数注释关系,以确保在运行时使用的实际引用肯定是有效的。
使用生命周期防止悬空引用
生命周期的主要目的是防止悬空引用,悬空引用会导致程序引用的数据不是它想引用的数据。
考虑下面的程序,它有一个外部作用域和一个内部作用域。
fn main() {let r;{let x = 5;r = &x;}println!("r: {r}");
}
错误信息:
外部作用域声明了一个名为 r 的变量,没有初始值,而内部作用域声明了一个名为 x 的变量,初始值为 5。在内部作用域中,我们尝试将r的值设置为对 x 的引用。然后,内部作用域结束,我们尝试在 r 中打印该值。
这段代码无法编译,因为 r 的生命周期比 x 更长,引用了 x 超出作用域时被释放的内存。
那么 Rust 如何判断这段代码是无效的呢?它使用借用检查器。
借用检查器
Rust 编译器有一个借用检查器,用于比较作用域以确定是否所有借用都有效。
借用检查器确保数据存活的时间长于其引用(Outlive)。
fn main() {let r; // ---------+-- 'a// |{ // |let x = 5; // -+-- 'b |r = &x; // | |} // -+ |// |println!("r: {r}"); // |
}
这里,我们用 'a 注释了 r 的生命周期,用 'b 注释了 x 的生命周期。内部的 'b 块比外部的 'a 生命周期块要小得多。在编译时,Rust 比较两个生命周期的大小,发现 r 的生命周期为 'a,但它引用的内存的生命周期为 'b。程序被拒绝,因为 'b 比 'a 短,即数据(引用的主体)没有引用的生命周期长。
修正程序:
fn main() {let x = 5; // ----------+-- 'b// |let r = &x; // --+-- 'a |// | |println!("r: {r}"); // | |// --+ |
} // ----------+
这里,x 的生命周期为 'b,在这种情况下大于 'a。这意味着 r 可以引用 x,因为 Rust 知道 r 中的引用总是有效的,而 x 是有效的。
函数中的泛型生命周期
我们尝试编写一个函数,输入两个字符串切片,返回两个字符串切片中较长的那个。
fn longest(x: &str, y: &str) -> &str {if x.len() > y.len() { x } else { y }
}fn main() {let string1 = String::from("abcd");let string2 = "xyz";let result = longest(string1.as_str(), string2);println!("The longest string is {result}");
}
编译报错了:
帮助文本表明,返回类型需要一个泛型生命周期参数,因为 Rust 无法判断被返回的引用是指向 x 还是 y。实际上,我们也不知道,因为这个函数体中的if块返回对x的引用,而else块返回对y的引用!
当我们定义这个函数时,我们不知道传入的引用的具体生存期,也不知道函数返回 x 的引用还是 y 的引用,因此不能通过查看作用域的方式确定返回的引用是否始终有效。借用检查器也无法确定这一点,因为它不知道 x 和 y 的生存期与返回值的生存期之间的关系。
为了修复这个错误,我们将添加泛型生命周期参数来定义引用之间的关系,以便借用检查器可以执行其分析。函数修改如下:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }
}
为什么这样写,后面有解释,我们先了解生命周期注释语法。
生命周期注释语法
生存期注释不会改变任何引用的生存时间。相反,它们描述了多个引用之间的生命周期关系。
正如当签名指定泛型类型参数时,函数可以接受任何类型一样,通过指定泛型生命周期参数,函数可以接受具有任何生命周期的引用。
生命周期注释的语法略有不同:生命周期参数的名称必须以撇号(')开头,并且通常都是小写且非常短,就像泛型类型一样。大多数人使用名称 'a 作为第一个生命周期注释。我们将生命周期形参注释放在引用的 & 之后,使用空格将注释与引用的类型分开。
这里有一些例子:
&i32 // a reference
&'a i32 // a reference with an explicit lifetime
&'a mut i32 // a mutable reference with an explicit lifetime
一个生命周期注释本身没有太多意义,因为注释的目的是告诉 Rust 多个引用的泛型生命周期参数是如何相互关联的。
让我们来看看在 longest 函数的上下文中,生命周期注释是如何相互关联的。
函数签名中的生命周期注解
要在函数签名中使用生命周期注释,我们需要在函数名和参数列表之间的尖括号内声明泛型生命周期参数,就像我们对泛型类型参数所做的那样。
我们希望签名表达以下约束:只要两个参数都有效,返回的引用就有效。这是参数的生存期和返回值之间的关系。我们将生命周期命名为 a,然后将其添加到每个引用中。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }
}
在函数中注释生命周期时,注释放在函数签名中,而不是函数体中。生命周期注释成为函数契约的一部分,就像签名中的类型一样。
让函数签名包含生命周期契约意味着 Rust 编译器所做的分析可以更简单。如果函数的注释方式或调用方式有问题,编译器错误可以更精确地指向我们的代码部分和约束。相反,如果 Rust 编译器对我们想要的生命周期关系做出更多推断,那么编译器可能只能指出代码的使用与问题的原因有许多步之隔。
请记住,当我们在这个函数签名中指定生命周期参数时,我们不会改变传入或返回的任何值的生命周期。相反,我们指定借用检查器应该拒绝不遵守这些约束的任何值。请注意,longest 函数不需要确切地知道 x 和 y 将存在多长时间,只需要某些作用域可以替换 'a 以满足此签名。
longest 函数的签名向我们保证:参数中的 x 和 y、返回值 str 的生命周期至少与生命周期 'a 一样长。
示例 1:
fn main() {let string1 = String::from("long string is long");{let string2 = String::from("xyz");let result = longest(string1.as_str(), string2.as_str());println!("The longest string is {result}");}
}
在本例中,string1 在外部作用域结束之前都是有效的,string2、result 在内部作用域结束之前都是有效的。编译通过。
示例 2:
fn main() {let string1 = String::from("long string is long");let result;{let string2 = String::from("xyz");result = longest(string1.as_str(), string2.as_str());}println!("The longest string is {result}");
}
编译报错:
编译器规定 string2 必须在外部作用域结束之前有效。我们使用相同的生命周期形参 'a 注释了函数参数和返回值的生命周期,这就告诉 Rust:longest 函数返回的引用的生命周期与传入的引用的生命周期中较小的那个相同。
从生命周期的角度思考
指定生命周期参数的方式取决于函数正在做什么。
例如,如果 longest 函数始终返回第一个参数,则不需要在 y 形参上指定生命周期,因为 y 的生命周期与 x 或返回值的生命周期没有任何关系。
fn longest<'a>(x: &'a str, y: &str) -> &'a str {x
}
当从函数返回引用时,返回类型的生命周期参数需要与其中一个参数的生命周期参数匹配。因为如果返回的引用不指向其中一个形参,则必须指向在此函数中创建的值。然而,这将是一个悬空引用。
fn longest<'a>(x: &str, y: &str) -> &'a str {let result = String::from("really long string");result.as_str()
}
这个实现无法编译,因为即使我们为返回类型指定了一个生命周期参数 'a,返回值的生命周期与参数的生命周期根本无关。我们无法指定改变悬空引用的生命周期参数,Rust 也不允许我们创建悬空引用。
一句话概括,生命周期语法是为了连接函数的各种参数和返回值的生命周期。一旦它们连接起来,Rust 就有足够的信息来允许内存安全的操作,并禁止可能创建悬空指针或违反内存安全的操作。
结构定义中的生命周期注解
结构体可以保存引用,但在这种情况下,我们需要在结构定义中的每个引用上添加一个生命周期注释。
struct ImportantExcerpt<'a> {part: &'a str,
}fn main() {let novel = String::from("Call me Ishmael. Some years ago...");let first_sentence = novel.split('.').next().unwrap();let i = ImportantExcerpt {part: first_sentence,};
}
这个结构体有一个字段 part,它保存一个字符串切片,这是一个引用。与泛型数据类型一样,在结构体名称后面的尖括号内声明泛型生命周期形参的名称,以便可以在结构体定义的主体中使用该生命周期形参。这个注释意味着 ImportantExcerpt 的实例不能比它在 part 字段中保存的引用的生命周期更长。
这里的 main 函数创建了一个 ImportantExcerpt 结构体的实例,该结构体包含对变量 novel 所拥有的 String 的第一个句子的引用。novel 中的数据在 ImportantExcerpt 实例创建之前就已经存在。此外, novel 直到 ImportantExcerpt 退出作用域后才会退出作用域,因此 ImportantExcerpt 实例中的引用是有效的。
省略生命周期
由前文得知,每个引用都有生命周期,并且需要为使用引用的函数或结构指定生命周期参数。
但凡是都有例外,看这个例子:
fn first_word(s: &str) -> &str {let bytes = s.as_bytes();for (i, &item) in bytes.iter().enumerate() {if item == b' ' {return &s[0..i];}}&s[..]
}
在早期版本(1.0 之前)的 Rust 中,这段代码无法编译,因为每个引用都需要显式的生命周期。必须写成这样:
fn first_word<'a>(s: &'a str) -> &'a str {
在编写了大量 Rust 代码之后,Rust 团队发现 Rust 程序员在特定情况下会一次又一次地输入相同的生命周期注释。这些情况是可以预测的,并遵循一些确定的模式。于是,开发人员将这些模式编程到编译器的代码中,这样借用检查器就可以推断出这些情况下的生存期,而不需要显式注释。
这叫做生命周期省略规则。这些不是程序员要遵循的规则,而是编译器将考虑的一组特殊情况。如果代码符合这些情况,则不需要显式地编写生命周期。
省略规则不提供完整的推理。如果在 Rust 应用这些规则之后,引用的生存期仍然存在歧义,编译器将不会猜测剩余引用的生存期应该是什么,而是直接报错。
函数或方法参数的生命周期称为输入生命周期,返回值的生命周期称为输出生命周期。
当没有显式注释时,编译器使用 3 条规则来计算引用的生命周期。第一条规则适用于输入生命周期,第二条和第三条规则适用于输出生命周期。如果编译器到达这三条规则的末尾,并且仍然有无法计算出生存期的引用,编译器将停止并报错。这些规则适用于 fn 定义和 impl 块。
- 规则一:编译器为每个引用形参分配一个生命周期形参。
- 规则二:如果只有一个输入生命周期参数,则将该生命周期赋给所有输出生命周期参数。
- 规则三:如果有多个输入生命周期参数,但其中一个是 &self 或 &mut self,self 的生命周期被分配给所有的输出生命周期参数。
我们尝试扮演编译器,应用这些规则来计算下列 first_word 函数签名中引用的生命周期。
fn first_word(s: &str) -> &str {
应用规则一,指定每个参数都有自己的生命周期,按惯例用 'a 表示:
fn first_word<'a>(s: &'a str) -> &str {
应用规则二,因为只有一个输入生命周期,则指定将输入参数的生命周期分配给输出生命周期:
fn first_word<'a>(s: &'a str) -> &'a str {
现在,这个函数签名中的所有引用都有生命周期,通过了。
让我们看另一个例子:
fn longest(x: &str, y: &str) -> &str {
应用规则一,指定每个参数都有自己的生命周期:
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
规则二不适用,因为存在多个输入生命周期。规则三也不适用,因为 longest 是一个函数而不是一个方法,所以没有一个参数是 self。在研究了这三条规则之后,我们仍然没有弄清楚返回类型的生命周期是多少。这就是编译出错的原因:编译器遍历了生命周期省略规则,但仍然无法计算出签名中引用的所有生命周期。
方法定义中的生命周期注释
在具有生命周期的结构体上实现方法时,使用与泛型类型参数相同的语法,如清单10-11所示。在哪里声明和使用生命周期参数取决于它们是否与结构体字段或方法参数和返回值相关。
结构字段的生命周期名称总是需要在 impl 关键字之后声明,然后在结构名之后使用,因为这些生命周期是结构类型的一部分。
在 impl 块内的方法签名中,引用可能与结构体字段中引用的生命周期相关联,或者它们可能是独立的。此外,生命周期省略规则通常使得方法签名中不需要生命周期注释。
以 ImportantExcerpt 结构体为例,首先,我们将使用一个名为 level 的方法,其唯一的参数是对 self 的引用,其返回值是 i32,而 i32 不是对任何东西的引用。
impl<'a> ImportantExcerpt<'a> {fn level(&self) -> i32 {3}
}
必须在 impl 之后声明生命周期参数,并在类型名之后使用它,但我们不需要注释对 self 引用的生命周期。
下面是应用规则三的示例:
impl<'a> ImportantExcerpt<'a> {fn announce_and_return_part(&self, announcement: &str) -> &str {println!("Attention please: {announcement}");self.part}
}
有两个输入生命周期,因此 Rust 应用规则一给 &self 和 announcement 分别指定生命周期。然后,因为其中一个参数是 &self,应用规则三,返回类型获得 &self 的生命周期。至此,方法参数、返回值都拥有了生命周期,编译通过。
静态生命周期
我们需要讨论的一个特殊生命周期——静态生命周期,它表示受影响的引用可以在程序的整个持续时间内存在。
我们可以这样注释:
let s: &'static str = "I have a static lifetime.";
该字符串的文本直接存储在程序的二进制文件中,该文件总是可用的。因此,所有字符串字面值都有静态生命周期。
泛型类型参数、trait 约束和生命周期
以最后一个大一统的例子收尾:
use std::fmt::Display;fn longest_with_an_announcement<'a, T>(x: &'a str,y: &'a str,ann: T,
) -> &'a str
whereT: Display,
{println!("Announcement! {ann}");if x.len() > y.len() { x } else { y }
}
longest_with_an_announcement 函数有一个名为 ann 的泛型类型 T 的参数,它可以由任何实现 where 子句指定的 Display trait 的类型填充。
函数主体中,ann 参数将使用 {} 打印,这就是为什么需要绑定 Display trait 的原因。
因为生命周期是泛型类型,所以生命周期参数 'a 和泛型类型参数 T 的声明位于函数名后面尖括号内的同一列表中。
相关文章:
Rust 学习笔记:生命周期
Rust 学习笔记:生命周期 Rust 学习笔记:生命周期使用生命周期防止悬空引用借用检查器函数中的泛型生命周期生命周期注释语法函数签名中的生命周期注解从生命周期的角度思考结构定义中的生命周期注解省略生命周期方法定义中的生命周期注释静态生命周期泛型…...
科学标注法:数据治理的未来之路
在数据治理领域,科学标注法是一种系统化、标准化的数据标注方法论,其核心是通过规范化的流程、技术工具和质量控制机制,将原始数据转化为具有语义和结构特征的可用数据资源。以下从定义、技术特征、应用场景、与传统标注方法的区别以及遵循的标准框架等方面展开详细解析: 一…...
小白刷题 之 如何高效计算二进制数组中最大连续 1 的个数
前言 学习如何快速找出二进制数组中最长的连续 1 序列。 这个问题在数据处理、网络传输和算法面试中经常出现,掌握它不仅能提升编程能力,还能加深对数组操作和循环控制的理解。 🌟 问题背景 想象你是一位网络工程师,正在分析服…...
中科方德鸳鸯火锅平台使用教程:轻松运行Windows应用!
原文链接:中科方德鸳鸯火锅平台使用教程:轻松运行Windows应用! Hello,大家好啊,今天给大家带来一篇中科方德鸳鸯火锅平台使用的文章,欢迎大家分享点赞,点个在看和关注吧!在信创环境…...
完全禁用 Actuator 功能
问题描述: springboot 关闭Actuator无效,原本设置 management:endpoints:enabled-by-default: false # 禁用所有端点屏蔽了/actuator/info和/actuator/health,但/actuator还可以访问。 拉满配置如下,成功屏蔽 # application.y…...
Netty学习专栏(二):Netty快速入门及重要组件详解(EventLoop、Channel、ChannelPipeline)
文章目录 前言一、快速入门:5分钟搭建Echo服务器二、核心组件深度解析2.1 EventLoop:颠覆性的线程模型EventLoop 设计原理核心 API 详解代码实践:完整使用示例 2.2 Channel:统一的网络抽象层Channel 核心架构核心 API 详解代码实践…...
27-FreeRTOS的任务管理
一、FreeRTOS的任务概念 在FreeRTOS中,任务(Task)是操作系统调度的基本单位。每个任务都是一个无限循环的函数,它执行特定的功能。任务可以被看作是一个轻量级的线程,具有自己的堆栈和优先级。下面是如何定义一个任务函…...
upload-labs靶场通关详解:第14关
一、分析源代码 这一关的任务说明已经相当于给出了答案,就是让我们上传一个图片木马,可以理解为图片中包含了一段木马代码。 function getReailFileType($filename){$file fopen($filename, "rb");$bin fread($file, 2); //只读2字节fclose…...
supervisor的进程监控+prometheus+alertmanager实现告警
supervisor服务进程监控实现告警 前提:部署了prometheus(配置了rules文件夹),alertmanager,webhook,python3环境 [roottest supervisor_prometheus]# pwd /opt/supervisor_prometheus [roottest supervisor_prometheus]# ls supervisor_exporter.py supervisor_int…...
HarmonyOS 鸿蒙应用开发基础:父组件调用子组件方法的几种实现方案对比
在ArkUI声明式UI框架中,父组件无法直接调用子组件的方法。本文介绍几种优雅的解决方案,并作出对比分析,分析其适用于不同场景和版本需求。帮助开发者在开发中合理的选择和使用。 方案一:Watch装饰器(V1版本适用&#x…...
Enhancing Relation Extractionvia Supervised Rationale Verifcation and Feedback
Enhancing Relation Extraction via Supervised Rationale Verification and Feedback| Proceedings of the AAAI Conference on Artificial Intelligencehttps://ojs.aaai.org/index.php/AAAI/article/view/34631 1. 概述 关系抽取(RE)任务旨在抽取文本中实体之间的语义关...
等离子体隐身技术和小型等离子体防御装置设计
相信大家前不久都看到了关于国防科大团队关于等离子体防御的相关文章,恰好也在做相关的研究,所以想向对这个问题感兴趣的朋友聊一聊这里面的一些基本原理和研究现状。 等离子体与电磁波的相互作用 等离子体会对电磁波产生吸收和反射作用,通常…...
PCB设计教程【入门篇】——电路分析基础-电路定理
前言 本教程基于B站Expert电子实验室的PCB设计教学的整理,为个人学习记录,旨在帮助PCB设计新手入门。所有内容仅作学习交流使用,无任何商业目的。若涉及侵权,请随时联系,将会立即处理 一、电路基本概念 连接线与节点 …...
C++-继承
1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象 程序设计的层…...
25.5.22学习总结
ST表(Sparse Table,稀疏表)是一种用于高效解决静态区间最值查询(RMQ)问题的数据结构。其核心思想是通过预处理每个长度为2^j的区间的最值,使得查询时只需合并两个子区间的最值即可得到结果,从而…...
接口自动化测试框架(pytest+allure+aiohttp+ 用例自动生成)
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 近期准备优先做接口测试的覆盖,为此需要开发一个测试框架,经过思考,这次依然想做点儿不一样的东西。 接口测试是比较讲究效率的…...
FastAPI在 Nginx 和 Docker 环境中的部署
目录 实现示例1. 项目结构2. FastAPI 应用 (app/main.py)3. 依赖文件 (app/requirements.txt)4. Dockerfile5. Nginx 配置 (nginx/nginx.conf)6. Docker Compose 配置 (docker-compose.yml) 使用方法修改代码后更新 实现示例 接下来创建一个简单的示例项目,展示如何…...
08 接口自动化-用例管理框架pytest之fixtrue,conftest.py,allure报告以及logo定制
文章目录 一、使用fixture实现部分前后置1.function级别:在每个函数的前后执行2.class级别:在每个类的前后执行一次3.module级别:在每个模块的前后执行一次4.package、session级别,一般是和connftest.py文件一起使用 二、当fixture的级别为pa…...
Appium+python自动化(二)- 环境搭建—下
简介 我这里已经将android的测试开发环境已经搭建准备完毕。上一篇android测试开发环境已经准备好, 那么接下来就是appium的环境安装和搭建了。 搭建环境安装过程中切勿浮躁,静下心来一个一个慢慢地按照步骤一个个来。 环境装好后,可以用真机…...
浅谈测试驱动开发TDD
目录 1.什么是TDD 2.TDD步骤 3.TDD 的核心原则 4.TDD 与传统开发的对比 5.TDD中的单元测试和集成测试区别 6.总结 1.什么是TDD 测试驱动开发(Test-Driven Development,简称 TDD) 是一种软件开发方法论,核心思想是 “先写测试…...
MVC和MVVM架构的区别
MVC和MVVM都是前端开发中常用的设计模式,都是为了解决前端开发中的复杂性而设计的,而MVVM模式则是一种基于MVC模式的新模式。 MVC(Model-View-Controller)的三个核心部分:模型、视图、控制器相较于MVVM(Model-View-ViewModel)的三个核心部分…...
网络安全-等级保护(等保) 3-1-1 GB/T 28448-2019 附录A (资料性附录)测评力度附录C(规范性附录)测评单元编号说明
附录A (资料性附录)测评力度 A.1 概述 测评力度是在等级测评过程中实施测评工作的力度,体现为测评工作的实际投入程度,具体由测评的广度和深度来反映。测评广度越大,测评实施的范围越大,测评实施包含的测评对象就越多。测评深度…...
MySQL 可观测性最佳实践
MySQL 简介 MySQL 是一个广泛使用的开源关系型数据库管理系统(RDBMS),以其高性能、可靠性和易用性而闻名,适用于各种规模的应用,从小型网站到大型企业级系统。 监控 MySQL 指标是维护数据库健康、优化性能和确保数据…...
深入解析Spring Boot与Redis集成:高效缓存与性能优化
深入解析Spring Boot与Redis集成:高效缓存与性能优化 引言 在现代Web应用中,缓存技术是提升系统性能的重要手段之一。Redis作为一种高性能的内存数据库,广泛应用于缓存、会话管理和消息队列等场景。本文将详细介绍如何在Spring Boot项目中集…...
《C 语言字符串操作从入门到实战(下篇):strncpy/strncat/strstr 等函数原理与实现》
目录 七. strncpy函数的使用与模拟实现 7.1 strncpy函数理解 7.2 strncpy函数使用示例 7.3 strncpy函数模拟实现 八. strncat函数的使用与模拟实现 8.1 strncat函数理解 8.2 strncat函数使用示例 8.3 strncat函数模拟实现 九. strncmp函数的使用 9.1 strncmp函数理…...
百度智能云千帆AppBuilder RAG流程技术文档
一、概述 本文档旨在详细阐述百度智能云千帆AppBuilder的RAG(Retrieval-Augmented Generation,检索增强生成)流程,包括API对接、知识库维护以及文档资料管理等关键环节。通过本流程,开发者可以高效地构建基于大模型的…...
程序编辑器快捷键总结
程序编辑器快捷键总结 函数跳转 函数跳转 Creator : F2VSCode : F12visual Studio : F12...
MySQL中实现大数据量的快速插入
一、SQL语句优化 1. 批量插入代替单条插入 单条插入会频繁触发事务提交和日志写入,效率极低。批量插入通过合并多条数据为一条SQL语句,减少网络传输和SQL解析开销。 -- 低效写法:逐条插入 INSERT INTO table (col1, col2) VALUE…...
从零基础到最佳实践:Vue.js 系列(8/10):《性能优化与最佳实践》
引言 Vue.js 是一个轻量、灵活且易于上手的现代前端框架,因其响应式数据绑定和组件化开发而广受欢迎。然而,随着项目规模的增长,性能问题逐渐显现,例如首屏加载缓慢、页面渲染卡顿、内存占用过高等。性能优化不仅能提升用户体验&…...
欧拉降幂(JAVA)蓝桥杯乘积幂次
这个题可以使用欧拉降幂,1000000007是质数,所以欧拉函数值为1000000006. import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System…...
Mysql的MVCC机制
MySQL的MVCC机制主要通过以下几个关键要素来工作: 数据版本与隐藏列 - MySQL InnoDB存储引擎会在每行数据中添加几个隐藏列,用于实现MVCC。其中包括 DB_TRX_ID 列,记录最后一次修改该行数据的事务ID; DB_ROLL_PTR 列ÿ…...
spring中的BeanFactoryAware接口详解
一、接口定义与核心作用 BeanFactoryAware 是 Spring 框架提供的一个回调接口,允许 Bean 在初始化阶段获取其所属的 BeanFactory 实例。该接口定义如下: public interface BeanFactoryAware {void setBeanFactory(BeanFactory beanFactory) throws Bea…...
mysql 创建用户,创建数据库,授权
创建一个远程用户 create user test% identified by test1111; 创建一个数据库并指定编码 create database testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 授权 grant all privileges on testdb.* to test%; 应用更改: FLUSH PRIVILEGES; 注意…...
Android 网络全栈攻略(三)—— 从三方库原理来看 HTTP
前面两篇文章我们介绍了 HTTP 协议的请求方法、请求码以及常用的请求头/响应头的知识。本篇会从 OkHttp 配置的角度来看这些框架是如何实现 HTTP 协议的,目的是加深对 HTTP 的理解,并学习协议是如何落地的。我们会选取 OkHttp 中与协议实现相关的源码作为…...
BlazeMeter录制jmeter脚本
文章目录 chrome安装blazeMeter插件开始录制 chrome安装blazeMeter插件 开始录制 1、点击重置按钮 2、输入名称 3、点击开始录制 4、打开浏览器操作 5、回到录制页面点击stop(注意,不要在第四步操作的那个窗口点停止) 6、点击save 7、保存jmeter脚本 8、将jmeter脚…...
SQL的RAND用法和指定生成随机数的范围
SQL中的RAND函数能够满足多种随机数生成的需求。通过合理地使用种子、结合一些SQL语句,我们可以实现灵活的随机数生成。在数据填充、数据处理、数据分析中经常需要用RAND生成的随机数。 用法1 生成随机浮点数,其返回值在0(包括0)…...
PHP7内核剖析 学习笔记 第七章 面向对象
面向对象编程,简称OOP,是一种程序设计思想。面向对象把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象一直是软件开发领域内比较热门的话题,它更符合人类看待事物的一般规律。与Java不同,PHP并…...
地信GIS专业关于学习、考研、就业方面的一些问题答疑
整理了地信GIS专业学生问得最多的几个问题:关于GIS专业学习、考研以及就业方面;大家可以一起来探讨一下。 学习方面 1、 作为一名GISer需要哪些核心素养或能力? 答:GIS是个交叉学科,涉及到地理学、地质学、测绘、遥感…...
构建可重复的系统 - SRE 的 IaC 与 CI/CD 基础
构建可重复的系统 - SRE 的 IaC 与 CI/CD 基础 还记得我们在第一篇提到的 SRE 核心原则之一——减少琐事 (Toil) 吗?想象一下手动配置服务器、部署应用程序、管理网络规则……这些任务不仅耗时、重复,而且极易出错。当系统规模扩大时,手动操作很快就会变得难以为继。SRE 的核…...
CQF预备知识:一、微积分 —— 1.2.2 函数f(x)的类型详解
文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。 📖 数学入门全解 本教程为复习课程,旨在帮助读者复习数学知识。教程涵盖以下四个主题: 微积分线性代数微…...
PyQt学习系列03-动画与过渡效果
PyQt学习系列笔记(Python Qt框架) 第三课:PyQt的动画与过渡效果 一、动画与过渡效果概述 1.1 动画与过渡的区别 动画(Animation):用于描述对象属性随时间变化的过程(如位置、颜色、大小&…...
偏微分方程数值方法指南及AI推理
偏微分方程(PDE)是我们用来描述科学、工程和金融领域中各种现象的语言——从流体流动和热传递到波的传播和金融衍生品的定价。然而,这些方程的解析解通常难以获得,尤其是在处理复杂几何形状或非线性行为时。这时,数值方…...
flask允许跨域访问如何设置
flask允许跨域访问 在Flask中,允许跨域访问通常涉及到CORS(跨源资源共享)策略。Flask本身并不直接提供CORS支持,但你可以通过安装和使用第三方库如Flask-CORS来轻松实现跨域资源共享。 安装Flask-CORS 首先,你需要安装Flask-CORS。你可以使用pip来安装它: pip instal…...
深度学习模型部署:使用Flask将图像分类(5类)模型部署在服务器上,然后在本地GUI调用。(全网模型部署项目步骤详解:从模型训练到部署再到调用)
个人github对应项目链接: https://github.com/KLWU07/Image-classification-and-model-deployment 1.流程总览 2.图像分类的模型—Alexnet 3.服务器端部署及运行 4.本地PyCharm调用—GUI界面 一、流程总览 本项目方法还是使用Flask 库,与之前一篇机器学…...
在Pycharm中如何安装Flask
(推荐)方法一:在Pycharm中创建项目之后,再安装Flask 1:在创建Pycharm时,解释器类型选择第一个:项目venv(自动生成的虚拟环境),在左下角选择终端(…...
基于Scikit-learn与Flask的医疗AI糖尿病预测系统开发实战
引言 在精准医疗时代,人工智能技术正在重塑临床决策流程。本文将深入解析如何基于MIMIC-III医疗大数据集,使用Python生态构建符合医疗AI开发规范的糖尿病预测系统。项目涵盖从数据治理到模型部署的全流程,最终交付符合DICOM标准的临床决策支…...
解决前端路由切换导致Keycloak触发页面刷新问题
使用window.location.href进行页面跳转时,浏览器会完全刷新页面,这会导致当前的JavaScript上下文被清空。 如果你的登录状态依赖于某些临时存储(如LocalStorage或sessionStorage),而这些存储在页面刷新后未正确初始化或丢失,就会导致用户被认为未登录。触发keycloak再次登录导…...
基于大模型的胫腓骨干骨折全周期预测与治疗方案研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 1.3 国内外研究现状 二、大模型技术原理与应用基础 2.1 大模型的基本架构与算法 2.2 医疗数据的收集与预处理 2.2.1 数据收集 2.2.2 数据预处理 2.3 模型训练与优化 2.3.1 模型训练过程 2.3.2 参数调整与超…...
智慧交通的核心引擎-车牌识别接口-车牌识别技术-新能源车牌识别
在数字化与智能化浪潮席卷交通运输领域的今天,车牌识别接口功能正以其精准、高效的特性,成为构建智慧交通体系的关键技术支撑。通过自动采集、识别车牌信息并实现数据互通,该功能已被深度融入交通管理、物流运输、出行服务等多个场景…...
小白的进阶之路系列之三----人工智能从初步到精通pytorch计算机视觉详解上
计算机视觉是教计算机看东西的艺术。 例如,它可能涉及构建一个模型来分类照片是猫还是狗(二元分类)。 或者照片是猫、狗还是鸡(多类分类)。 或者识别汽车出现在视频帧中的位置(目标检测)。 或者找出图像中不同物体可以被分离的位置(全视分割)。 计算机视觉应用在…...