Rust学习笔记004:Rust的所有权机制

news2025/1/23 11:01:59

内存相关的基础知识

不同语言的内存管理系统

在这里插入图片描述

栈和堆

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

堆和栈的使用

在这里插入图片描述
在这里插入图片描述

引出所有权方案

在这里插入图片描述

String类型

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Rust 的所有权机制

  • Rust 的所有权机制是一种内存管理系统,它允许在编译时通过所有权、借用和生命周期来确保内存安全,同时避免了垃圾回收的运行时开销。这些概念共同构成了 Rust 强大的所有权系统,通过编译时的检查来防止一类内存错误,如空悬指针和双重释放等。这种系统使得 Rust 具有内存安全性、线程安全性和零成本抽象等特性。

1. 所有权规则:

  • 每个值都有一个所有者: 在任意时刻,一个值只能有一个所有者。
  • 所有者离开作用域时,值会被销毁: 当拥有某个值的变量离开其作用域时,Rust 会自动调用该值的 Drop trait 中的 drop 方法来释放其占用的资源。

2. 移动(Move):

  • 当将一个值赋值给另一个变量时,所有权会从一个变量移动到另一个变量。这会导致原来的变量无法再使用该值。
let s1 = String::from("Hello");// 可以使用 from 函数从字符串字面值创建出 String 类型
let s2 = s1; // 所有权移动到变量 y
// println!("{}", x); // 这里编译器会报错,因为 x 不再拥有值的所有权
  • 隐含的一个设计原则: Rust 不会自动创建数据的深拷贝,就运行时性能而言,任何自动赋值的操作都是廉价的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
相关:C++中,移动构造函数
  • 在C++中,移动构造函数(Move Constructor)是一种特殊的构造函数,用于在对象的所有权被转移(移动)时创建新对象。移动构造函数通常用于提高性能,特别是在涉及资源管理的情况下,比如使用动态内存分配的对象。

  • 移动构造函数是通过右值引用(Rvalue Reference)来实现的。在C++11及以后的标准中,可以通过定义移动构造函数来支持右值引用。移动构造函数的目标是在没有不必要的资源复制的情况下,将资源从一个对象“移动”到另一个对象,以提高效率。

  • 以下是一个简单的示例,演示了移动构造函数的用法:

#include <iostream>
#include <string>

class MyString {
public:
    // 移动构造函数
    MyString(MyString&& other) noexcept {
        std::cout << "Move constructor called" << std::endl;
        data = other.data;
        size = other.size;
        other.data = nullptr;
        other.size = 0;
    }

    // 构造函数
    MyString(const char* str) {
        size = strlen(str);
        data = new char[size + 1];
        strcpy(data, str);
    }

    // 析构函数
    ~MyString() {
        delete[] data;
    }

private:
    char* data;
    size_t size;
};

int main() {
    MyString str1("Hello");
    MyString str2 = std::move(str1); // 使用移动构造函数

    return 0;
}

在上述例子中,MyString 类具有移动构造函数。在 main 函数中,通过 std::movestr1 的所有权移动给了 str2。移动构造函数被调用后,str1 的资源被移动到 str2,同时 str1 的数据成员被置为 nullptr

注意:在移动构造函数中,我们通常将被移动对象的数据成员设置为安全状态,以避免资源重复释放。此外,通常需要在移动构造函数中使用 noexcept 来指定该函数不会抛出异常,以便在一些情况下提供更好的性能。

移动构造函数对于提高性能和避免不必要的资源复制是非常有用的,特别是在处理大型数据结构、动态分配内存等情况下。

3. 克隆(Clone,Copy):感觉类似c++的深拷贝构造

在这里插入图片描述

如果需要拷贝堆上数据而不是移动所有权,可以使用 clone 方法。但这会增加内存开销。

let x = String::from("Hello");
let y = x.clone(); // 创建了一个新的 String 对象,所有权移动到变量 y
println!("x: {}, y: {}", x, y); // 这样是合法的,因为 x 仍然有效

在这里插入图片描述

4. 借用(Borrowing):

通过借用,可以暂时获取对值的引用而不移动所有权。借用分为可变借用和不可变借用。

fn main() {
    let s1 = String::from("Hello");
    let len = calculate_length(&s1); // 通过引用借用 s1
    println!("Length of '{}' is: {}", s1, len); // 这里依然可以使用 s1,因为只是借用了引用

    // 可变借用
    let mut s2 = String::from("Rust");
    modify_string(&mut s2); // 通过可变引用借用 s2
    println!("Modified string: {}", s2);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

fn modify_string(s: &mut String) {
    s.push_str(" is awesome!");
}

5. 生命周期(Lifetime):

生命周期是用于描述引用有效范围的标记。Rust 的生命周期系统确保引用在其所引用的值有效的情况下才能被使用。

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

fn main() {
    let s1 = String::from("Rust");
    let s2 = String::from("C");

    let result;
    {
        let s3 = String::from("Java");
        result = longest(s1.as_str(), s3.as_str());
    } // s3 的生命周期结束,result 引用的值仍然是有效的
    println!("The longest string is: {}", result);
}

在上述例子中,longest 函数使用了生命周期参数 'a,它表示返回的引用的生命周期与输入参数的生命周期一致。

所有权与函数

在 Rust 中,所有权系统与函数的参数传递和返回密切相关,它确保在函数调用过程中对所有权的正确管理。

在这里插入图片描述

1. 所有权传递:

当你将一个值传递给函数时,它的所有权会被转移给函数。这意味着在函数中你可以使用该值,但在函数返回后,调用者将无法再使用它。

在这里插入图片描述

fn take_ownership(s: String) {
    println!("Received: {}", s);
    // s 的所有权在这里结束,s 的内存将被释放
}

fn main() {
    let my_string = String::from("Hello");
    take_ownership(my_string); // my_string 的所有权被传递给 take_ownership 函数
    // println!("Value: {}", my_string); // 这里编译器会报错,因为 my_string 已经失去了所有权
}

2. 返回所有权:

函数也可以返回所有权,将所有权还给调用者。这可以通过在函数签名中指定返回类型为 -> 加上类型名。

在这里插入图片描述

fn return_ownership() -> String {
    let s = String::from("Returned");
    s // 所有权被返回给调用者
}

fn main() {
    let result = return_ownership(); // 调用 return_ownership 后,result 拥有了返回的所有权
    println!("Result: {}", result);
}

3. 引用传递:

  • 在所有权用完后,再返回回来?
    在这里插入图片描述

  • 如果你想在函数中使用值但不获取其所有权,可以使用引用传递。引用允许你在不移动所有权的情况下访问值。

在这里插入图片描述

fn borrow_value(s: &String) {
    println!("Borrowed: {}", s);
    // s 是引用,所有权不会在这里转移
}

fn main() {
    let my_string = String::from("Hello");
    borrow_value(&my_string); // 传递了 my_string 的引用
    println!("Value: {}", my_string); // 这是合法的,因为并未传递所有权
}

可变引用
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

字符串切片

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023-12-21 LeetCode每日一题(美丽塔 II)

2023-12-21每日一题 一、题目编号 2866. 美丽塔 II二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。 你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i &#xff0c;高度为 heights[i] 。 如果以下条件满足&a…

软件工程PPT 笔记摘录(2)

分析软件需求 UML 提供了用例图来分析和描述用例视角的软件需求模型 UML 提供了交互图和状态图来描述行为视角的软件需求模型 UML 提供了类图来描述和分析业务领域的概念模型 顺序图&#xff1a;强调消息传递的时间序 通信图&#xff1a;突出对象间的合作 类图&#xff0…

【SAP-FICO】--总账标识配置路径OBXR

FICO业务需求&#xff1a; F-02&#xff0c;财务会计凭证填写09客户A时&#xff0c;带出的总账标识为可编辑。 需求截图&#xff1a; 第一步&#xff1a;了解需求 首先&#xff0c;我们要明白&#xff0c;财务凭证生成&#xff0c;是分多种类型&#xff08;不同类型的凭证&a…

【深度学习:Few-shot learning】理解深入小样本学习中的孪生网络

【深度学习&#xff1a;Few-shot learning】理解深入小样本学习中的孪生网络 深入理解孪生网络&#xff1a;架构、应用与未来展望小样本学习的诞生元学习小样本学习孪生网络的基本概念孪生网络的细节Triplet Loss架构特点关键组件训练过程主要应用领域未来展望示例图片结论 备注…

[JS设计模式]Prototype Pattern

Prototype pattern Prototype pattern可便于同类型的多个对象共享属性。原型&#xff08;prototype&#xff09;是JS原生的对象&#xff0c;其他对象可以通过原型链&#xff08;prototype chain&#xff09;来访问原型。单独看这句描述可能还是有点儿抽象&#xff0c;下面通过…

【HarmonyOS】ArkTS语言介绍与组件方式运用

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…

OSG绘制视锥体

最近要来实现一个相机位姿态可视化的需求&#xff0c;不想使用pangolin&#xff0c;不好集成&#xff0c;想用osg来做可视化。以下是demo效果。 代码实现&#xff1a; // Cone_of_vision.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <os…

Angular进阶之六:Progressive rendering

简介 Progressive Rendering 是一种提高 Web 应用性能的方法&#xff0c;允许页面在加载过程中逐步呈现&#xff0c;以提高用户体验。在本文中&#xff0c;我们将探讨如何在 Angular 中通过自定义指令实现 Progressive Rendering&#xff0c;特别是处理从服务器获取大量数据的…

PAT 乙级 1046 划拳

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就赢了&#xff0c;输家罚一杯酒。两人同赢或两人同输则继续下一轮&…

数据预处理时,怎样处理类别型特征?

1. 序号编码 序号编码通常用于处理类别间具有大小关系的数据。例如成绩&#xff0c;可以分为低、中、高三档&#xff0c;并且存在“高>中>低”的排序关系。序号编码会按照大小关系对类别型特征赋予一个数值ID&#xff0c;例如高表示为3、中表示为2、低表示为1&#xff0…

【网络安全 | MD5截断比较】PHP、Python脚本利用

前言 在解题中&#xff0c;当遇到类似 substr(md5(a),-6,6) 7788这样的MD5截断比较的题目时&#xff0c;只有求出a的值才能进行接下来的操作。 一个一个去猜是不可能的&#xff0c;通常使用脚本解决&#xff0c;文末给出实战案例。 PHP循环脚本 <?phpfor($i1;$i<9…

机器学习(一) -- 概述

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理 未完待续…… 目录 系列文章目录 前言 一、机器学习定义&#xff08;是什么&#xff09; 二、机器学习的应用&#xff08;能做什么&#xff09; 三、***机器…

蒙牛的京东店铺的数字化经营

1、蒙牛的京东店铺的数字化经营框架是怎样的&#xff1f; 2. 蒙牛的京东店铺是如何进行环境分析的&#xff1f; 结合波特五力模型进行分析&#xff1a;客户、供应商、企业自身、潜在竞争对手、同行业竞争对手 3.蒙牛的京东店铺采取了哪些方式进行线上引流&#xff1f; 找智商长…

2023-12-23 LeetCode每日一题(移除石子使总数最小)

2023-12-23每日一题 一、题目编号 1962. 移除石子使总数最小二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 piles &#xff0c;数组 下标从 0 开始 &#xff0c;其中 piles[i] 表示第 i 堆石子中的石子数量。另给你一个整数 k &#xff0c;请你执行下述…

Zookeeper-Zookeeper应用场景实战(二)

1. Zookeeper 分布式锁实战 1.1 什么是分布式锁 在单体的应用开发场景中涉及并发同步的时候&#xff0c;大家往往采用Synchronized&#xff08;同步&#xff09;或者其他同一个 JVM内Lock机制来解决多线程间的同步问题。在分布式集群工作的开发场景中&#xff0c;就需要 一种…

Spring Cloud Gateway + Nacos 实现动态路由

1、maven 依赖 主要依赖 <!-- 网关 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>案件差不多完整主要依赖 <!--Spring boot 依赖(微服务基…

LLM之RAG实战(九)| 高级RAG 03:多文档RAG体系结构

在RAG&#xff08;检索和生成&#xff09;这样的框架内管理和处理多个文档有很大的挑战。关键不仅在于提取相关内容&#xff0c;还在于选择包含用户查询所寻求的信息的适当文档。基于用户查询对齐的多粒度特性&#xff0c;需要动态选择文档&#xff0c;本文将介绍结构化层次检索…

四种常见智能指针的介绍

一、介绍 当类中有指针成员时&#xff0c;一般有两种方式来管理指针成员&#xff1a;一是采用值型的方式管理&#xff0c;每个类对象都保留一份指针指向的对象的拷贝&#xff1b;另一种更优雅的方式是使用智能指针(smart pointer)&#xff0c;从而实现指针指向的对象的共享。 …

UDP协议基本原理

前言 本文主要讲解传输层中的UDP协议&#xff0c;我准备从UDP的特点出发&#xff0c;深入理解UDP协议&#xff0c;从UDP协议的结构推出UDP协议的特点&#xff1b; 一、理解端口号 前面我们总是说用IP加端口号的方式定位全网的唯一进程&#xff0c;通常在TCP/IP中&#xff0c;我…

gitee(码云)仓库内容更新,使用TortoiseGit同步本地仓库和远程仓库

前言&#xff1a; 网上有很多同步仓库教程&#xff0c;但都是git命令行操作。这篇使用TortoiseGit可视化操作同步本地仓库和远程仓库 克隆本地仓库&#xff0c;上传远程仓库&#xff0c;下载TortoiseGit可以看这篇使用gitee&#xff08;码云&#xff09;上传自己的代码&#xf…