30天拿下Rust之所有权

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

概述

        在编程语言的世界中,Rust凭借其独特的所有权机制脱颖而出,为开发者提供了一种新颖而强大的工具来防止内存错误。这一特性不仅确保了代码的安全性,还极大地提升了程序的性能。在Rust中,所有权是一种编译时检查机制,用于追踪哪些内存或资源何时可以被释放。每当一个变量被赋予一个值(比如:字符串、数组或文件句柄)时,Rust会确定这个变量是否“拥有”这个值,拥有资源的变量负责在适当的时候释放这些资源。

所有权的规则

        在Rust中,每个值都有一个被称为“所有者”的变量。同一时间内,这个值只能有一个所有者,并且当所有者(变量)离开作用域时,该值会被自动释放,不需要我们手动释放,这就是所谓的“所有权”。这意味着Rust通过编译期检查,强制执行资源生命周期管理,从根本上杜绝了内存泄漏问题。

        Rust的所有权规则非常简单,只有以下三条,但却非常有效。

        1、单一所有者:在任何给定的时间,只有一个变量可以拥有某个资源。这确保了不会出现数据竞争,因为只有一个所有者可以修改或释放资源。

        2、移动语义:当资源从一个变量转移到另一个变量时,所有权也随之移动。这意味着原始变量不再拥有资源,新变量现在负责释放资源。这种转移是通过“移动”操作来完成的,这类似于C++ 11中的移动语义。

        3、释放资源:当拥有资源的变量离开其作用域时,Rust会自动释放该资源。这确保了不会发生内存泄漏,因为资源总是在不再需要时被清理。

栈和堆

        在Rust中,值是位于栈上还是堆上,在很大程度上影响了语言的行为。因此,在继续介绍下面的内容之前,我们有必要先学习下栈和堆的知识。

        当一个函数被调用时,它的局部变量和参数通常会被分配在栈上。当函数执行完毕返回时,这些变量会自动被清理。栈内存的访问速度非常快,因为栈具有连续的内存空间,CPU可以直接通过指针运算访问栈上的数据。但栈的大小通常是有限制的,因为栈是后进先出的数据结构。如果递归调用过深或者分配了过多的局部变量,可能会导致栈溢出。

        堆内存由程序员(或编程语言运行时)手动分配和释放。在Rust中,使用String、Vec等数据时,数据通常会被分配在堆上。由于堆内存是分散的,访问堆上的数据通常比访问栈上的数据要慢。堆的大小通常比栈大得多,并且没有严格的后进先出限制,这使得堆适合存储生命周期不确定或需要大量内存的数据。

移动和克隆

        在Rust中,数据的移动和克隆是处理数据所有权和交互的两种非常重要的机制。

        对于栈上的数据,赋值时,数据是直接克隆或拷贝的,不涉及移动的概念。一些基本数据类型(包括:整型、浮点型、布尔型、字符型、仅包含以上类型的元组)对应的变量不需要存储到堆上,都是存储到栈上的。

fn main() {
    let x = 5;
    let y = x;
    // 栈上的数据,赋值时进行克隆
    println!("{0} {1}", x, y);
}

        对于堆上的数据,赋值时,默认是进行移动的。当数据通过值传递时,会发生数据的移动。这意味着数据的所有权会从发送方转移到接收方。一旦数据被移动,原始数据就不再有效,因为它不再拥有数据的所有权。

fn main() {
    let str1 = String::from("Hello, CSDN");
    // str1的所有权会移动到str2
    let str2 = str1;
  
    // 会提示编译错误:value borrowed here after move
    // println!("str1: {}", str1);

    // str2现在拥有所有权
    println!("str2: {}", str2);
}

        在上面的示例代码中,str1的所有权被移动到了str2,因此str1不再有效。如果我们尝试使用str1,Rust编译器会报错。

        对于堆上的数据,如果我们既想要保留原始数据的所有权,又想让另一个变量拥有相同的数据,可以使用clone方法来创建数据的一个副本。在Rust中,不是所有的类型都实现了Clone特征,但对于那些实现了Clone的类型(比如:String、Vec等),我们可以调用clone方法来创建一个新的副本。

fn main() {
    let str1 = String::from("Hello, CSDN");
    // 创建str1的副本,而不是移动所有权
    let str2 = str1.clone();
  
    // str1仍然拥有所有权
    println!("str1: {}", str1);

    // str2拥有str1的副本
    println!("str2: {}", str2);
}

        在上面的示例代码中,str1.clone() 创建了str1的一个副本,并将所有权赋给了str2。这样,str1和str2都拥有有效的数据,并且都可以独立地使用。

        注意:clone方法通常涉及到数据的深拷贝,这可能会消耗额外的内存和性能。因此,在需要频繁复制大型数据结构时,应该考虑其他策略,比如:使用引用或智能指针来共享所有权。

所有权的使用

        在Rust中,函数与所有权的关系是紧密相联的。函数涉及的所有权主要有两种:一种是函数参数的所有权,另一种是函数返回值的所有权。

        1、函数参数的所有权。当你通过值传递一个变量给函数时,该变量的所有权会转移到函数中。函数内部可以自由地修改和使用这个变量,而原始变量在函数调用后将不再有效。这种所有权转移,确保了数据在函数中的安全性和一致性。

struct Data {
    value: i32,
}

fn process_data(data: Data) {
    // data获得了所有权
    println!("{}", data.value);
    // 函数结束时,data的所有权会被释放
}

fn main() {
    let cur_data = Data { value: 66 };
    // 将cur_data的所有权传递给process_data函数
    process_data(cur_data);
    // my_data的所有权已经被转移,故下面的代码会提示编译错误
    // println!("{}", cur_data.value);
}

        在上面的示例代码中,我们定义了一个名为Data的结构体,它包含一个i32类型的字段。当我们把这个结构体变量cur_data作为参数传递给process_data函数时,cur_data的所有权被转移到了函数的参数data中。因此,在process_data函数执行期间,data可以被自由地使用。但一旦函数执行完毕,cur_data的所有权就被释放了,因此我们不能在后面再次访问它,否则会导致编译错误。

        2、函数返回值的所有权。函数可以返回值,而返回值的所有权会转移到调用方。这意味着,调用方负责该值的生命周期。

fn greet(name: String) -> String {
    let text = format!("Hello, {}", name);
    // 当函数返回text时,它的所有权将被转移到调用方
    return text;
}

fn main() {
    // 创建一个String,并将其所有权传递给greet函数
    let name = String::from("CSDN");

    // 调用greet函数,并获得返回值的所有权
    let result = greet(name);
    println!("{}", result);
}

总结

        Rust的所有权模型是一种独特而强大的工具,也是一套严谨而灵活的编程范式。它确保了内存安全,简化了并发编程,并赋予了开发者更高的控制力,使他们能够编写出既安全又高效的软件。这是Rust区别于其他现代编程语言的独特魅力所在,也是其在系统级编程、网络服务、嵌入式开发等各个领域大放异彩的重要原因。文章来源地址https://www.toymoban.com/news/detail-837252.html

到了这里,关于30天拿下Rust之所有权的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Rust】Rust学习 第四章认识所有权

    所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全。因此,理解 Rust 中所有权如何工作是十分重要的。 4.1 所有权 所有运行的程序都必须管理其使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时不断地

    2024年02月13日
    浏览(51)
  • Rust-所有权(ownership)

    Rust入门学习系列-Rust 的核心功能(之一)是 所有权(ownership)。引入这个概念是为了更好的管理计算机的内存。下面篇幅让我们来研究下这个功能有什么神奇之处。 常见的编程语言中计算机内存管理方式: Java:Java使用Java虚拟机(JVM)来管理计算机内存。JVM有一个垃圾回收

    2024年02月19日
    浏览(37)
  • Rust核心功能之一(所有权)

    目录 1、什么是所有权? 1.1 所有权规则  1.2 变量作用域 1.3 String 类型 1.4 内存与分配 变量与数据交互的方式(一):移动 变量与数据交互的方式(二):克隆 只在栈上的数据:拷贝 1.5 所有权与函数 1.6 返回值与作用域 所有权(系统)是 Rust 最为与众不同的特性,对语言的

    2024年02月04日
    浏览(41)
  • rust学习——栈、堆、所有权

    栈和堆是编程语言最核心的数据结构,但是在很多语言中,你并不需要深入了解栈与堆。 但对于 Rust 这样的系统编程语言,值是位于栈上还是堆上非常重要, 因为这会影响程序的行为和性能。 栈和堆的核心目标就是为程序在运行时提供可供使用的内存空间。 栈 栈按照顺序存

    2024年02月07日
    浏览(71)
  • 【rust】| 06——语言特性 | 所有权

    系列文章目录 【rust】| 00——开发环境搭建 【rust】| 01——编译并运行第一个rust程序 【rust】| 02——语法基础 | 变量(不可变?)和常量 【rust】| 03——语法基础 | 数据类型 【rust】| 04——语法基础 | 函数 【rust】| 05——语法基础 | 流程控制 【rust】| 06——语言特性 | 所有权  

    2024年02月04日
    浏览(44)
  • Rust-所有权和移动语义

    拿C语言的代码来打个比方。我们可能会在堆上创建一个对象,然后使用一个指针来管理这个对象: 接下来,我们可能需要使用这个对象: 然而,这段代码之后,谁能猜得到,指针p指向的对象究竟发生了什么?它是否被修改过了?它还存在吗,是否已经被释放?是否有另外一个指

    2024年01月18日
    浏览(38)
  • Rust语言从入门到入坑——(5)Rust 所有权

    主要介绍Rust所有权的知识,涉及到变量的作用域,内存释放机制,移动,克隆,引用等知识,很多知识是Rust语言特有机制。 所有权有以下三条规则: - Rust 中的每个值都有一个变量,称为其所有者。 - 一次只能有一个所有者。 - 当所有者不在程序运行范围时,该值将被删除

    2024年02月10日
    浏览(44)
  • Rust语法:所有权&引用&生命周期

    垃圾回收管理内存 Python,Java这类语言在管理内存时引用了一种叫做垃圾回收的技术,这种技术会为每个变量设置一个引用计数器(reference counter),来统计每个对象的引用次数。 一旦某个对象的引用数为0,垃圾回收器就会择取一个时机将其所占用的空间回收。 以Python为例子

    2024年02月12日
    浏览(54)
  • 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念

    【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 本章节将讲解 Rust 独有的概念(所有权)。所有权是 Rust 最独特的特性,它使得 Rust 能够

    2024年02月10日
    浏览(44)
  • Rust 基础入门 —— 2.3.所有权和借用

    Rust 的最主要光芒: 内存安全 。 实现方式: 所有权系统 。 因为我们这里实际讲述的内容是关于 内存安全的,所以我们最好先复习一下内存的知识。 然后我们,需要理解的就只有所有权概念,以及为了开发便利,进一步引出的引用借用概念。 内存作为存储程序运行时数据

    2024年02月12日
    浏览(35)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包