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

内存相关的基础知识

不同语言的内存管理系统

在这里插入图片描述

栈和堆

在这里插入图片描述

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

堆和栈的使用

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

引出所有权方案

在这里插入图片描述

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); // 通过引用借用 s1println!("Length of '{}' is: {}", s1, len); // 这里依然可以使用 s1,因为只是借用了引用// 可变借用let mut s2 = String::from("Rust");modify_string(&mut s2); // 通过可变引用借用 s2println!("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.hqwc.cn/news/311937.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot+拦截器(Interceptor)

记录一下SpringBoot的拦截器(Interceptor)使用 拦截器(Interceptor)是AOP面向切面编程的思想来实现的&#xff0c;对于只写代码的来说&#xff0c;具体如何实现不需要多关心&#xff0c;只需要关心如何去使用&#xff0c;会用在那些地方。 当http请求进入Springboot应用程序后…

【Redis前奏曲】初识分布式

文章目录 一. 简单认识Redis二. 分布式系统1. 单机架构2. 应用服务和数据库服务分离3. 引入更多的应用服务器节点4. 数据库读写分离5. 多主机存储6. 微服务架构 三.常见名词解释应用(Application)/系统(System)模块(Module)/组件(Component)分布式(Distributed)集群(Cluster)主…

【HR非技术问题面试篇】你怎么看待加班?

你对加班怎么看待? &#x1f60a;老油条经典回答系列 &#x1f60a;老油条经典回答系列 这种问题&#xff0c;怎么回答都可以&#xff0c;我觉得重要的实时表达你自己。如果你就不想加班&#xff0c;也没必要勉强说自己爱加班&#xff0c;结果入职之后干的不开心。 不过&…

操作系统 全整理

第一章 第二章 进程控制 原语 进程创建 进程终止 进程阻塞和唤醒 进程切换 进程通信 共享数据空间 略过 消息传递 以格式化的消息通过发送、接收消息原语来进行数据交换 管道通信 什么是线程&#xff1f; 线程的实现方式 线程模型是由 线程的状态与转换 进程调度 高级调…

引领企业人工智慧转型的 5 个可行策略

人工智能的最新进展引发了企业AI转型&#xff0c;其规模、速度和不确定性程度都是巨大的。那些敢于大胆行动、走在时代前沿的企业&#xff0c;将能够抓住人工智能在几乎每个行业中带来的巨大增长和价值创造机会。这样做需要他们的领导人掌握人工智能作为二十一世纪通用技术的深…

网易有道词典不能截屏翻译,不能联网解决办法

对应版本&#xff1a; win10系统&#xff0c;联想拯救者笔记本&#xff0c;网易有道词典8.10.2.0。 网易有道词典免费下载链接&#xff1a;https://download.csdn.net/download/qq_42755734/88684985 修改代理&#xff1a; youdao.com 0 取消勾选---不更新 效果&#xff1a…

八. 实战:CUDA-BEVFusion部署分析-环境搭建

目录 前言0. 简述1. CUDA-BEVFusion浅析2. CUDA-BEVFusion环境配置2.1 简述2.2 源码下载2.3 模型数据下载2.4 基础软件安装2.5 protobuf安装2.5.1 apt 方式安装2.5.2 源码方式安装 2.6 编译运行2.6.1 配置 environment.sh2.6.2 利用TensorRT构建模型2.6.3 编译运行程序 2.7 拓展…

【SpringBoot】常用注解

RequestBody&#xff1a;自动将请求体中的 json 数据转换为实体类对象。 这个例子凑巧传入的json属性键名和User键名一致&#xff0c;可以直接使用User实体类对象&#xff0c;如果键名不一致则需要用一个Map 类接收参数&#xff1a; PutMapping("/update")public R…

我在 VSCode 插件里接入了 ChatGPT,解决了Bug无法定位的难题

作为一名软件开发者&#xff0c;我时常面临着代码中Bug的定位和解决问题。这个过程往往既费时又充满挑战。然而&#xff0c;最近我在我的VSCode插件中接入了ChatGPT&#xff0c;这个决定彻底改变了我处理Bug的方式。 Bug&#xff1a;开发者的噩梦 在开发过程中&#xff0c;遇…

HarmonyOS 组件通用属性之通用事件 文档参数讲解(点击事件)

我们组件中 会有很多通用的信息和方法 那么 首先 我们看通用事件 通用事件中 最常用的就是我们的点击事件 比如说 我们之前常写的 组件.onClick(()>{//事件逻辑 })但是 我们之前 都没有用它接参数 我们可以这样 Button("跳转").onClick((ewat: ClickEvent)>…

Gitee触发Jenkins403讨逆猴子-解决方案

Jenkins报&#xff1a;403 No valid crumb was included in the request 具体解决方案如下&#xff1a; 执行如下脚本内容&#xff1a; hudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION true成功后&#xff1a; Gitee再次测试&#xff1a…

统信系统常见问题解决方法

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 背景说明 本文所说的问题&#xff0c;是基于浪潮统信UOS的环境存在的问题。 一、WPS新建文档默认保存格式不对 解决办法&#xff1a; 1.编辑/opt/apps/cn.wps.wps-office-pro/files/kingsoft/wps-office/…