二-内存模型及所有权和引用、借用

2023-11-24 05:15

本文主要是介绍二-内存模型及所有权和引用、借用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 内存模型1

内存模型,heap和stack的区别,GC方面和go的区别

基本同go一样,分为堆内存、栈内存。栈内存函数退出时会自动释放,大小有限,一般是比较“小”的变量存到栈上。
比较“大”的或者大小动态变化的会分配到堆上。同时为了使用这个值,需要在栈上有一个变量指向这个堆的地址。
和go的区别在于,go是GC系统在运行时动态记录堆内存的使用情况,自己来清理,用户完全不用管。c这类完全交给用户处理,总是容易出错。
Rust介于两者之间,通过所有权和生命周期的机制,在编译阶段识别到堆内存的使用情况,等到不再被使用时,会自动清理。

2. String类型

整个高级点的东西,继续说明上面的内存问题,基于这种类型讲所有权、借用才有意义

这里的String类似go里面的字符切片,var stringSlice []byte,结构也类似,有一个结构体 包含指针、cap、len 三字表头,然后指针指向堆内存的一个 “底层数组”。
根据结构可知,既然涉及到堆内存,就关系到内存释放问题,对于Rust就是通过所有权和生命周期机制,“自动”释放内存。

使用示例如下:

// 注意 mut 声明的才可以继续进行修改操作
let mut string1 = String::from("String hello");
string1.push_str(", world");
println!("{}", string1);

3. 所有权,引用、可变引用、借用,

3.1 先看一个示例

fn main() {let mut s = String::from("Hello ");s.push_str("world");// 把s做为参数传给另一个函数,这个在go里很常见,会拷贝s的皮,但是用一套底层数组just_print(s); //  - value moved hereprintln!("{}", s);
}fn just_print(s: String) {// do some thingprintln!("{}", s);
}

这时学go同学惊呆了,后面s竟然是无效的了,感觉很不合理,明明有这个变量,竟然会无效;学c++的同学,可能联想到,如果这个指针,在最后一行打印之前,被Delete了,那的确会异常。
所以有GC语言的同学,如果接受不了,存在变量,但是无效的情况,可以结合C++想一下,这不就是写了个bug。

3.2 所有权转移

上文示例,其实就是所有权转移,Rust通过一个堆内的“对象”,只能有一个变量拥有它的所有权这种方式,就能很好的追踪何时可以自动GC,在编译的时候,追踪这个对象的所有权变量,以及这个变量的使用情况,就可以在不用的时候释放内存。

let string1 = String::from("a");
let string3 = string1; // 这里会发生所有权转移,此时string1就无效了 println!("{}", string1);报错。

这样的限制,避免一个堆内存被多个变量指向,一是写代码的人容易勿删导致悬垂引用,二是只有一份所有权的情况下,编译器就可以盯着有所有权的这个变量的生命周期的范围,从而知道啥时候到期进行自动GC

3.3 mut

先说说这个,这个其实比所有权 应用什么的简单很多,就是控制能不能修改而已。

通过示例可以知道,是不是可变的关键在于用let绑定或者传参的时候,有没有mut,和之前的那个变量是不是可变的无关。

// string3.push_str("afs"); // 这时不能
let mut string4 = string3;
string4.push_str("!!! change to mut.");
println!("{}", string4);

3.4 引用、可变引用、借用

所有权每次都要来回转移,只能转移到一个上面,很是麻烦,尤其是函数传参的情况,作为参数传进去之后,如果不再返回回来,编译器就认为这个堆内存的生命就到这了,就给GC了。
所以增加了引用的概念,让事情简单一些,也叫借用borrow,之前所有权转移叫 move。

let string4 = get_then_return(string4);// 这里甚至有整成了不可变的,所以mut相对随意,甚至如果所有的都加mut就和其他语言一样了,但是引用那里有限制。
println!("{}", string4);
let s = &string4;

可变引用又会导致数据竞争问题,

3.5 引用借用的关系

这两个词经常一起出现,后面看了Rust程序设计第二版才清楚。引用是对&这种方式的表述,借用则是表示了他真正的道理:所有借用,必须归还,即借用不会影响原有的生命周期,反而受原有变量的生命周期控制。
引用是一个用于指代另一个值的值,需要里面的数据时,可以解引用。这个在go语言中不存在,因为go只有值传递,没有引用传递。

fn main() {let a = 10;let ai = &a;assert_eq!(*ai, a);
}

这篇关于二-内存模型及所有权和引用、借用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/421299

相关文章

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

Golang基于内存的键值存储缓存库go-cache

《Golang基于内存的键值存储缓存库go-cache》go-cache是一个内存中的key:valuestore/cache库,适用于单机应用程序,本文主要介绍了Golang基于内存的键值存储缓存库... 目录文档安装方法示例1示例2使用注意点优点缺点go-cache 和 Redis 缓存对比1)功能特性

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

SpringBoot快速接入OpenAI大模型的方法(JDK8)

《SpringBoot快速接入OpenAI大模型的方法(JDK8)》本文介绍了如何使用AI4J快速接入OpenAI大模型,并展示了如何实现流式与非流式的输出,以及对函数调用的使用,AI4J支持JDK8... 目录使用AI4J快速接入OpenAI大模型介绍AI4J-github快速使用创建SpringBoot

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内