Rust-所有权(ownership)

2024-02-19 08:12
文章标签 rust ownership 所有权

本文主要是介绍Rust-所有权(ownership),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、管理计算机内存的方式
      • 所有权规则
  • 二、Rust中的 move
      • Copy trait
  • 三、Rust中的 clone
  • 总结


前言

Rust入门学习系列-Rust 的核心功能(之一)是 所有权(ownership)。引入这个概念是为了更好的管理计算机的内存。下面篇幅让我们来研究下这个功能有什么神奇之处。


一、管理计算机内存的方式

常见的编程语言中计算机内存管理方式:

  • Java:Java使用Java虚拟机(JVM)来管理计算机内存。JVM有一个垃圾回收器(GC),用于自动回收不再使用的对象并释放内存。
  • .NET:.NET使用托管堆来管理内存。在.NET中,对象分配在托管堆上,当对象不再使用时,垃圾回收器会自动回收内存。
  • Go:Go使用垃圾回收器(GC)来管理内存。Go的GC使用标记-清除算法来识别和清除不再使用的对象,并回收相关的内存。
  • JavaScript:JavaScript使用自动垃圾回收器来管理内存。JavaScript引擎会周期性地检查对象是否不再被引用,如果对象没有引用,则会将其标记为垃圾并回收相关的内存。
  • Rust:Rust使用所有权系统来管理内存。在Rust中,每个值都有一个所有者,并且只有当前所有者可以访问和修改该值。当值的所有者超出作用域时,该值将被自动释放。

通过上面的几种常用语言的列举分析,所有运行的程序都必须管理其使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时不断地寻找不再使用的内存;在另一些语言中,开发者必须亲自分配和释放内存。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。在运行时,所有权系统的任何功能都不会减慢程序。

所有权规则

那么所有权管理有什么规则?所有权的规则:

  • Rust 中的每一个值都有一个被称为其 所有者(owner)的变量。
  • 值在任一时刻有且只有一个所有者。
  • 当所有者(变量)离开作用域,这个值将被丢弃。

二、Rust中的 move

在Rust中,move操作指的是将变量的所有权从一个变量转移到另一个变量。当对某个值进行move操作时,该值将不再有效,不能再被访问或使用。

move操作通常发生在以下几种情况下:

  1. 将一个变量赋值给另一个变量时,会发生move操作。例如:
let a = String::from("Hello");
let b = a; // move操作,a的所有权转移到b
// println!("{}", a); // 这里会出现编译错误,a已经不再有效
  1. 函数参数传递时,会发生move操作。例如:
fn take_ownership(s: String) {// ...
}let s = String::from("Hello");
take_ownership(s); // move操作,s的所有权转移到函数take_ownership中
// println!("{}", s); // 这里会出现编译错误,s已经不再有效
  1. 函数返回值时,会发生move操作。例如:
fn create_string() -> String {let s = String::from("Hello");s // move操作,将s作为返回值
}let s = create_string(); // move操作,create_string函数的返回值所有权转移到s
// println!("{}", s); // 这里会出现编译错误,s已经不再有效

需要注意的是,通过clone()方法可以创建值的深拷贝,而不是move操作。例如:

let a = String::from("Hello");
let b = a.clone(); // 深拷贝,a的所有权不会转移
println!("{}", a); // 正常打印 Hello
println!("{}", b); // 正常打印 Hello

除了移动操作,我们还可以借用值的引用来使用它,而不会转移所有权。借用可以是不可变的(引用为&T)或可变的(引用为&mut T)。以下是一个示例:

fn main() {let s1 = String::from("hello");let len = calculate_length(&s1); // 通过引用借用s1值的所有权,计算长度println!("The length of '{}' is {}.", s1, len);// s1.push_str(", world!"); // 这一行代码将导致编译错误,因为我们只借用了s1的不可变引用let mut s2 = String::from("hello");change(&mut s2); // 通过可变引用借用s2的值的所有权,进行修改println!("s2 = {}", s2);
}fn calculate_length(s: &String) -> usize {s.len()
}fn change(s: &mut String) {s.push_str(", world!");
}

在这个例子中,我们将s1的引用传递给calculate_length函数,它只借用了s1的值的不可变引用来计算其长度,而没有转移所有权。我们还可以将s2的可变引用传递给change函数,它通过可变引用修改了s2的值。

Rust通过引用和所有权规则实现了借用和移动操作。通过移动操作,我们可以转移值的所有权到新的变量中。通过借用操作,我们可以共享值的引用,而不转移所有权。这种机制在Rust中确保了内存安全和线程安全。

Copy trait

下面的代码可以运行~

fn main() {let x = 5;let y = x;println!("x = {}, y = {}", x, y);
}

Rust 有一个叫做 Copy trait 的特殊标注,可以用在类似整型这样的存储在栈上的类型上。如果一个类型实现了 Copy trait,那么一个旧的变量在将其赋值给其他变量后仍然可用。

那么哪些类型实现了 Copy trait 呢?你可以查看给定类型的文档来确认,不过作为一个通用的规则,任何一组简单标量值的组合都可以实现 Copy,任何不需要分配内存或某种形式资源的类型都可以实现 Copy 。如下是一些 Copy 的类型:

所有整数类型,比如 u32。
布尔类型,bool,它的值是 true 和 false。
所有浮点数类型,比如 f64。
字符类型,char。
元组,当且仅当其包含的类型也都实现 Copy 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。

三、Rust中的 clone

Rust中的clone是一种方法,用于创建一个数据的完全副本。它会创建一个与原始数据相同的新数据,但是新数据独立于原始数据,具有自己的所有权。

在Rust中,数据的所有权规则决定了每个值在任何给定时间点只能有一个所有者。当我们将一个值赋给另一个变量时,所有权会转移给新变量。当我们通过引用来传递值时,所有权不会转移,只是借用该值。

使用clone方法可以在不转移所有权的情况下创建数据的完整副本。这对于需要在多个地方使用同一份数据时非常有用,而不想转移所有权。

以下是一个简单的示例,演示了clone方法的使用:

let s1 = String::from("hello");
let s2 = s1.clone();println!("s1 = {}, s2 = {}", s1, s2);

在这个例子中,我们创建一个字符串s1,然后通过调用clone方法创建了一个s2的副本。两个变量现在都拥有自己的所有权,并且可以独立于彼此使用。

需要注意的是,clone方法是一个昂贵的操作,因为它会对数据进行深拷贝。在处理大型数据结构时,应该谨慎使用clone,以避免性能问题。

clone方法是Rust中用于创建完整副本的方法,而不转移数据所有权。它对于需要在不同地方使用相同数据副本的场景非常有用。


总结

Rust 是一种系统级编程语言,其最重要的特性是所有权系统。这个特性可以使程序员避免许多常见的内存安全问题。

在 Rust 中,每个值都有一个所有者。这个所有者负责分配和释放值的内存。当所有者离开作用域时,它会自动释放相应的内存。

Rust 的所有权系统通过三个规则来实现:

  1. 唯一性规则:每个值都只能有一个所有者。当值被分配给另一个所有者时,原来的所有者将失效。这可以有效防止两个所有者同时释放同一个内存。

  2. 移动语义:当将值赋给另一个变量时,它将从原来的变量中移动到新的变量中。这意味着原来的变量将失效,并且不能再使用它。这确保了所有权的唯一性规则。

  3. 借用规则:可以通过借用来暂时地使用一个值,而不改变所有权。借用是通过引用来实现的,借用的变量称为引用。引用只是对值的一个视图,它不具备所有权。借用规则规定了如何正确地使用和管理引用。

总结来说,Rust 的所有权系统通过唯一性规则、移动语义和借用规则保证了内存的安全性和有效性。这使得 Rust 可以在不使用垃圾回收机制的情况下,实现高性能和安全的系统级编程。

参考: Rust 中文文档

这篇关于Rust-所有权(ownership)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(

第二十四章 rust中的运算符重载

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust中的运算符重载 目录 注意一、前言二、基本使用三、常用运算符四、通用约束 一、前言 C/C++中有运算符重载这一概念,它的目的是让即使含不相干的内容也能通过我们自定义的方法进行运算符操作运算。 比如字符串本身是不能相加的,但由于C++中的String重载了运算符+,所以我们就可以将两个字符串进行相加、但实际

【Rust光年纪】Rust 机器人学库全景:功能、安装与API概览

机器人学+Rust语言=无限可能:六款库带你开启创新之旅! 前言 随着机器人技术的快速发展,对于机器人学领域的高效、可靠的编程语言和库的需求也日益增加。本文将探讨一些用于 Rust 语言的机器人学库,以及它们的核心功能、使用场景、安装配置和 API 概览,旨在为机器人学爱好者和开发人员提供参考和指导。 欢迎订阅专栏:Rust光年纪 文章目录 机器人学+Rust语言=无限可能:

第二十二章 rust数据库使用:sea-orm详解

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust数据库使用:sea-orm详解 目录 注意一、前言二、项目管理三、迁移文件四、实体文件五、业务使用 一、前言 只要开发稍微大型一点的项目,数据库都是离不开的。 rust目前并没有特别成熟的数据库框架,sea-orm这个框架是我目前所看到的成熟度最高的一个,并且仍在积极开发中。 所以本文将以sea-orm框

Rust使用之【宏】

一、简单使用clap clap = { version = "4.5.17", features = ["derive"] } 其中,什么是features = ["derive"]:表示你希望在添加 clap 依赖时启用 derive 特性。这通常意味着你希望使用 clap 的派生(derive)宏功能,这些功能可以简化创建命令行接口的代码。例如,derive 特性可以让你使用 #[der

第二十一章 rust与动静态库的结合使用

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust与动静态库的结合使用 目录 注意一、前言二、库生成三、库使用四、总结 一、前言 rust中多了很多类型的库,比如前面章节中我们提到基本的bin与lib这两种crate类型库。 如果你在命令行执行下列语句: rustc --help 那么你将能找到这样的内容: --crate-type [bin|li

Rust的常数、作用域与所有权

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一  -CSDN博客 Rust到底值不值得学,之二-CSDN博客 Rust的数据类型-CSDN博客 3.7  常数的数据类型 在Rust语言中,变量有类型,常量也有类型。我们知道,在定义const常量的时候,就要

搭建Rust的开发环境

目标 我没有使用过Rust,但我听说它是一个可靠的语言,可以保证内存安全和线程安全。我对此很有兴趣,就想试一试这个语言。 在官网上有介绍他们所推荐的编辑器: 我将选择 Visual Studio Code (关于 【Visual Studio】和【Visual Studio Code】的区别:【VS】是完整的集成开发环境,而【VSCode】只算的上是一个相对轻量级的文本编辑器,并附带一些便捷

Rust的数据类型

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一  -CSDN博客 Rust到底值不值得学,之二-CSDN博客 3.5  数据类型的定义和分类 在Rust编程中,所谓数据类型,就是对数据存储的安排,包括存储单元的长度(占多少字节)以及数据的存储形式。不同的