当前位置: 首页 > news >正文

rust:什么是所有权

什么是所有权

所有权是用于控制Rust程序如何管理内存的一种规则。所有程序都必须管理他们在运行时使用的内存,有些语言有垃圾回收机制,自动查找不再使用的内存,并将其释放。Rust使用所有权对内存进行管理。所有权的任何功能都不能在程序运行时减慢速度。

所有权规则

  • 每个值都有一个所有者
  • 一个值在同一时间只能有一个所有者
  • 当所有者离开作用域时,值被自动清理

变量作用域

作用域 就是一个变量“能被使用”的代码范围。

use std::io;fn main(){{   let s = String::from("hello"); println!("{}", s);             } println!("{}",s);
}

{}内作为一个作用域,s变量只在{}内有效,出了{}就不再有效,代码块内部的输出语句输出hello,代码块外部的输出语句已经离开作用域,不再有效。

我们已经见过字符串字面量了,就是那些直接写在代码里的字符串值。这种写法虽然方便,但并不是所有场景都适用。

一方面,字符串字面量是 “固定不变” 的,一旦写死就改不了了。另一方面,写代码的时候,我们不可能知道所有要用到的字符串。比如,想获取用户输入的内容并保存,这时候就没法用字面量了。针对这些情况,Rust 提供了第二种字符串类型 ——String。它能把数据存在堆内存里,所以就算编译时不知道具体要存多少文本,也能灵活应对。你可以用 from 函数,从字符串字面量创建出 String 类型的数据。

let s = String::from("hello");
双冒号 :: 运算符允许我们将此特定 from 命名空间 函数,而不是使用某种名称。

这种字符串可以编译,如下所示代码

let mut s = String::from("hello");s.push_str(", world!"); println!("{s}"); 

push将一个字符串追加到已有的字符串,所以输出是hello,world!

内存和分配

咱们可以把字符串文字(比如代码里直接写的 "hello")和程序的关系,类比成 “印刷好的书” 和 “临时笔记” 的区别:

字符串文字就像书里印好的固定内容。比如你写代码时写了 let s = "你好",这个 "你好" 在程序编译的时候(相当于印刷厂印书的时候)就已经确定了 —— 内容不会变,长度也固定。所以编译器会直接把它 “刻” 进最终的程序文件里(就像文字印在书页上)。等程序运行时(相当于你翻开书看),直接就能从程序里找到这段文字,不用临时找地方存,也不用操心它会不会变,所以速度特别快、效率很高。这一切的前提是:它从出生到结束都不会变(不变性),所以才能这么 “省心” 地提前安排好。但不是所有文字都能这么处理。比如用户在键盘上输入的内容(你写程序时根本不知道用户会输入啥,可能是 10 个字,也可能是 1000 个字),或者程序运行中需要动态改的文字(比如把 "hello" 改成 "hello world",长度变了)。这些文字在编译时(印书时)根本确定不了 —— 既不知道具体内容,也不知道会占多大地方,甚至运行时还会变。这种情况就没法提前 “印” 进程序里了,只能在程序运行时,临时向电脑申请一块内存来存(就像你拿张白纸临时记笔记,内容多少不确定,还能随时涂改)。这就是为什么 Rust 里有 String 这种类型,专门用来处理这种 “动态变化” 的文本。

对于 String 类型,为了支持可变、可增长的文本片段,我们需要在堆上分配一定量的内存(在编译时未知)来保存内容。这意味着:

  • 必须在运行时请求内存
  • 在完成String后,将此内存释放

当s超出范围时,我们可以把String所需的内存返回给内存分配器。当变量超出作用域时,Rust为我们调用一个特殊的函数,这个函数叫做drop,Rust在}时会自动调用drop

变量和数据的交互

在 Rust 中,多个变量可以以不同的方式与相同的数据进行交互。

整型

let x = 10;
let y = x;

将10赋值给x变量,将x变量的值赋值给y变量,因为整数是具有已知的固定大小的简单值,这两个 5 值被推送到堆栈上。

String类型

 let s1 = String::from("hello");let s2 = s1;

将“hello”赋值给s1,再将s1的值赋值给s2,

在这里插入图片描述

字符串由指针、长度、容量三个部分组成。这组数据存储在堆栈上,右侧是堆上保存内容的内存。

在这里插入图片描述

当一个变量超出范围时,Rust 会自动调用 drop 函数并清理该变量的堆内存。该图显示了指向同一位置的两个数据指针。当 s2s1 超出范围时,它们都会尝试释放同一个内存。这被称为双重自由错误,是内存安全错误之一。释放内存两次可能会导致内存损坏,从而可能导致安全漏洞。

为了保证内存安全,在 let s2 = s1; 之后,Rust 认为 s1 不再有效。因此,当 s1 超出范围时,Rust 不需要释放任何内容。

fn main(){let s1 = String.from("hello");let s2 = s1;println!("{s1},world!");
}

当程序这样写,调用s1时会出现以下错误,因为 Rust 阻止你使用无效的引用:

cargo runCompiling guessing_game v0.1.0 (D:\desktop\Rust代码\guessing_game\guessing_game)
error[E0382]: borrow of moved value: `s1`--> src\main.rs:40:16|
38 |     let s1 = String::from("hello");|         -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
39 |     let s2 = s1;|              -- value moved here
40 |     println!("{s1},world!");|                ^^ value borrowed here after move|= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable|
39 |     let s2 = s1.clone();|                ++++++++For more information about this error, try `rustc --explain E0382`.
error: could not compile `guessing_game` (bin "guessing_game") due to 1 previous error; 4 warnings emitted

范围和分配

可以把变量想象成一个 “专属储物盒”,盒子里装着数据(内存里的内容),而 “所有权” 就是 “这个盒子归谁管” 的凭证 —— 每个盒子同一时间只归一个变量管。

当你给一个变量赋新值时,相当于 “把盒子里原来的东西拿出来,换成新东西”。这时候,原来的东西因为没人管了(变量的所有权已经转到新值上了),Rust 会立刻叫 “清洁工”(drop函数)来把原来的东西清走,释放它占的空间。

fn main() {let mut s = String::from("hello");s = String::from("rust");println!("{s}");
}

在这里插入图片描述

我们声明一个变量 s 并将其绑定到一个 String,其值为 “hello”。然后我们立即创建一个值为 “world” 的新字符串并将其分配给 s

在这里插入图片描述

因此,原始字符串立即超出范围。Rust 将运行drop函数,它的内存将立即被释放。当我们打印值时 最后,它将是 rust

变量和数据的克隆

如果想深度赋值String的堆数据,而不是仅仅复制堆栈数据,我们可以用clone方法
nT-1761749942215)]

因此,原始字符串立即超出范围。Rust 将运行drop函数,它的内存将立即被释放。当我们打印值时 最后,它将是 rust

变量和数据的克隆

如果想深度赋值String的堆数据,而不是仅仅复制堆栈数据,我们可以用clone方法

http://www.dtcms.com/a/545985.html

相关文章:

  • 模版网站好吗搜索引擎最新排名
  • 【js逆向案例二】瑞数6 深圳大学某医院
  • 网站编辑怎么样东莞网站建设网站推广价钱
  • TypeScript声明合并详解一
  • 网站后台登录域名注册公司需要注册资金吗
  • 蓝牙钥匙技术详解:从基础原理到未来趋势 大纲
  • 基于SVM与HOG特征的交通标志检测与识别
  • 如何做能上传视频网站网页设计教程
  • 做网盟的网站必须备案wordpress发表的文章点不开
  • nextjs路由[[...slug]]与[...slug]的区别
  • 全国药品招标、投标常用数据渠道及数据库<很全>
  • 附录:glibc-2.4 pthread 源码简要(了解)
  • 网站注册费用济南网站优化哪里做的好
  • 晋中住房与城乡建设厅网站湖南手机版建站系统哪家好
  • 记类成员变量 vs 方法中的变量
  • 企业网站模板建站建网站浩森宇特
  • 项目(四)
  • 徐州 商城网站设计wordpress变为中文
  • Rust Feature Flags:编译期配置的艺术与工程实践
  • 贵金属网站建设阿里云域名备案查询
  • Java后台面试 常见问题
  • 如何自己建站网站制作深圳公司网站推广
  • 【RAG架构】RAG架构概要
  • 6.5 大数据方法论与实践指南-安全合规-账号体系
  • Vue 系列之:Vue2 双端 Diff 算法原理
  • 网站建设与维护案列领优惠券的网站怎么做
  • 【AIGC面试面经第四期】LLM-Qwen相关问答
  • 百度首页网站的设计用php做企业网站的可行性
  • 前端流水线连接npm私有仓库
  • 创可贴设计网站官网怎么建公司网站