Rust - 可变引用和悬垂引用

这篇具有很好参考价值的文章主要介绍了Rust - 可变引用和悬垂引用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 可变引用

在上一篇文章中,我们提到了借用的概念,将获取引用作为函数参数称为 借用borrowing),通常情况下,我们无法修改借来的变量,但是可以通过可变引用实现修改借来的变量。代码示例如下:

fn main() {
    let mut s = String::from("hello");  // s是可变的变量
    
    change(&mut s);  // &mut 表示可变引用
}

fn change(some_string: &mut String) {  // &mut 表示可变引用
    some_string.push_str(", world");
}

要想实现修改借来的变量就必须将 s改为 mut。然后必须创建一个可变引用 &mut s和接受一个可变引用 some_string: &mut String

但是可变引用有一个很大的限制:在特定作用域中的特定数据只能有一个可变引用。比如下述代码就不会被成功编译。

fn main() {
    let mut s = String::from("hello"); 
    
    let r1 = &mut s;
    let r2 = &mut s;
}

编译运行就会抛出如下异常:

error[E0499]: cannot borrow `s` as mutable more than once at a time
 --> src/main.rs:5:14
  |
4 |     let r1 = &mut s;
  |              ------ first mutable borrow occurs here
5 |     let r2 = &mut s;
  |              ^^^^^^ second mutable borrow occurs here
6 |
7 |     println!("{}, {}", r1, r2);
  |                        -- first borrow later used here

所以这种修改借来的变量的可变引用是以一种受限制的方式允许修改,这个限制的好处是 Rust 可以在编译时就避免数据竞争。数据竞争data race)类似于竞态条件,它可由这三个行为造成:

  • 两个或更多指针同时访问同一数据。
  • 至少有一个指针被用来写入数据。
  • 没有同步数据访问的机制。

数据竞争会导致未定义行为,难以在运行时追踪,并且难以诊断和修复;Rust 避免了这种情况的发生。我们可以使用{}创建一个新的作用域,这样就能够允许多个可变引用了,只是不能在同一个作用域中同时拥有:

fn main() {
    let mut s = String::from("hello");

	{
    	let r1 = &mut s;

	} // r1 在这里离开了作用域,所以我们完全可以创建一个新的引用

	let r2 = &mut s;
}

另外还需要注意的是,不能在拥有不可变引用的同时拥有可变引用。不可变引用的用户可不希望在他们的眼皮底下值就被意外的改变了!但是多个不可变引用是可以的,因为没有哪个只能读取数据的人有能力影响其他人读取到的数据。如下述代码:

fn main() {
    let mut s = String::from("hello");

    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    let r3 = &mut s; // 在拥有不可变引用的同时拥有可变引用

    println!("{}, {}, and {}", r1, r2, r3);

} 

上面代码示例编译时会抛出如下异常:

error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
 --> src/main.rs:6:14
  |
4 |     let r1 = &s; // no problem
  |              -- immutable borrow occurs here
5 |     let r2 = &s; // no problem
6 |     let r3 = &mut s; // BIG PROBLEM
  |              ^^^^^^ mutable borrow occurs here
7 |
8 |     println!("{}, {}, and {}", r1, r2, r3);
  |                                -- immutable borrow later used here

但是如果可变引用和不可变引用他们的作用域不重叠代码就是可以编译的,我们可以将上面的代码示例进行修改就可以正常运行了。

fn main() {
    let mut s = String::from("hello");

    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    println!("{} and {}", r1, r2);
    // 此位置之后 r1 和 r2 不再使用

    let r3 = &mut s; // 没问题
    println!("{}", r3);

}

悬垂引用(Dangling References)

在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。

当我们不小心创建了悬垂引用,Rust在编译的时候就会抛出异常:

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {  // dangle 返回一个字符串的引用
    let s = String::from("hello");  // s 是一个新字符串

    &s  // 返回字符串 s 的引用
}// 这里 s 离开作用域并被丢弃。其内存被释放。

因为 s是在 dangle函数内创建的,当 dangle的代码执行完毕后,s将被释放。不过我们尝试返回它的引用。这意味着这个引用会指向一个无效的 String,所以在编译时Rust就会抛出异常,解决方式就是直接返回String

fn no_dangle() -> String {
    let s = String::from("hello");

    s
}  // 所有权被移动出去,内存没有被释放

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

Rust - 可变引用和悬垂引用,软件测试,rust,开发语言,后端,软件测试,功能测试,自动化测试,程序人生

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

Rust - 可变引用和悬垂引用,软件测试,rust,开发语言,后端,软件测试,功能测试,自动化测试,程序人生文章来源地址https://www.toymoban.com/news/detail-814305.html

到了这里,关于Rust - 可变引用和悬垂引用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Rust 基础篇】Rust 解引用多态

    在 Rust 中,解引用多态(Deref Coercion)是一种特性,它允许自动进行类型转换,将实现了 Deref trait 的类型转换为目标类型的引用。通过解引用多态,我们可以更方便地使用不同类型的智能指针和引用。 本篇博客将详细介绍 Rust 中解引用多态的使用方法和相关概念,以及它在代

    2024年02月16日
    浏览(35)
  • 【Rust 基础篇】Rust 引用循环:解析和避免

    在 Rust 中,引用循环是指两个或多个对象之间相互引用,形成一个循环链。这种情况下,对象之间的引用计数永远不会变为零,导致内存泄漏和资源泄漏。本篇博客将详细介绍 Rust 引用循环的概念、问题和解决方案,并通过代码示例演示如何避免引用循环。 引用循环在 Rust

    2024年02月17日
    浏览(37)
  • 【软件测试】浅了解什么是软件测试及开发测试模型

    目录 1.什么是软件测试? 2.什么是需求? 3.什么是测试用例 4.什么是软件错误(bug)? 5.开发模型和测试模型 5.1软件的生命周期 5.2瀑布模型 5.3螺旋模型 5.4软件测试V模型 5.5软件测试w模型 6.软件测试的生命周期 7.bug的生命周期 最常见的理解是:软件测试就是找 BUG ,发现缺陷

    2023年04月19日
    浏览(87)
  • 【软件测试】软件测试的基本概念和开发模型

    在进行软件测试的学习之前,我们要了解软件测试一些基本概念. 这些基本概念将帮助我们更加明确工作的目标以及软件测试到底要做什么. 软件测试的基本概念有3个,分别是 需求,测试用例和BUG. 这里的需求还可以分为 用户需求和软件需求 ,用户需求: 简单理解为甲方提出的需求

    2023年04月15日
    浏览(123)
  • 软件测试/测试开发丨ChatGPT在软件测试领域的应用

    随着互联网技术的迅速发展,软件已经成为现代社会中不可或缺的一部分。而软件测试作为保障软件质量的关键环节,也越来越受到人们的关注。在这个领域,ChatGPT作为一种新型的人工智能技术,正逐渐应用于软件测试领域,为软件测试带来了诸多创新和改进。 在软件测试

    2024年02月14日
    浏览(63)
  • Soft:软件开发的简介(敏捷开发等6大软件开发模式)、软件测试的简介(单元测试/集成测试/系统测试/验收测试/回归测试、黑白灰功能测试、DEV等四套环境)、运维的简介之详细攻略

    Soft:软件开发的简介(敏捷开发等6大软件开发模式)、软件测试的简介(单元测试/集成测试/系统测试/验收测试/回归测试、黑白灰功能测试、DEV等四套环境)、运维的简介之详细攻略 目录 1、软件开发(敏捷开发等6大软件开发模式) Computer:敏捷开发Scrum方法的简介、发展历程、开

    2024年02月04日
    浏览(66)
  • 测试软件开发---软件缺陷章

    软件缺陷 软件出现缺陷一般是因为开发的流程规划不准确,需求不明确,或需求变更/在开发者开发的时候无法清晰的理解需求出现不同程度的偏差/客户方频繁的更改、更新需求也会影响到软件的质量 软件结构复杂、编码误差/错误、项目期限过短、项目中插入新的技术 处理

    2024年02月02日
    浏览(79)
  • Rust-解引用

    “解引用”(Deref)是“取引用”(Ref)的反操作。取引用,我们有、mut等操作符,对应的,解引用,我们有 操作符,跟C语言是一样的。示例如下: 比如说,我们有引用类型p:i32;,那么可以用 符号执行解引用操作。上例中,v1的类型是i32,p的类型是i32,*p的类型又返回i32。 解引用操作

    2024年01月19日
    浏览(41)
  • rust 引用怎么用

    文章会通过三个例子来了解 rust 所有权的机制,都是从应用的角度来说明,rust 所有权底层是如何实现会在后续的内容中介绍。 理解 RUST 所有权规则: RUST 中的每个值都有一个对应的变量作为它的所有者 同一时间内,值有且仅有一个所有者 当所有者离开自己的作用域时,它

    2024年02月16日
    浏览(47)
  • 【rust/esp32】wsl2开发环境搭建与测试

    esp型号:esp32s3 开发环境:wsl2 rustc版本:rustc 1.73.0-nightly esp idf版本:v5.1.1 目前是按照这个demo的流程可以跑通 修改demo中的部分代码,不然可能跑不通 以下这些问题奇奇怪怪,主要可能还是 rust toolchain 没有安装对 还有就是按照rust build中 espup 的流程执行之后,我还是继续执行

    2024年02月08日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包