首页 > 其他分享 >Rust所有权

Rust所有权

时间:2022-11-14 11:56:49浏览次数:32  
标签:rust 作用域 str1 let 内存 所有权 Rust

有的语言完全使用手动内存管理,程序员必须负责向分配器归还它们申请的空间,也就是说,必须要有一个free操作对应着一个allocate操作。另一些语言使用自动内存管理系统(俗称GC),它们完全接管内存的创建以及回收(在不需要的时候)。

  1. 手动内存管理对人类不友好,人很难保证不出错,而且在项目中的各个模块的互相调用中很难确定一个对象的内存该由谁来管理
  2. 自动内存管理中的GC总是需要占用程序一部分运行时间和内存来做垃圾收集,并且垃圾回收并不是即时的。

Rust使用第三种内存管理方式,即——所有权系统。

所有权规则

  1. Rust中的每个都有一个所有者(owner)
  2. 值在任意一刻有且只有一个所有者
  3. 当所有者(变量)离开作用域,这个值将会被丢弃

上面所说的是,值具有所有者,所谓所有者就是当前承载该值的变量,一定要搞清值和所有者的概念和区别。

变量作用域

{   // 进入作用域,目前s不可用
    let s = String::from("HHH");  // 创建s,目前s可用
    // s可用
} // 离开作用域,s不可用

这和其它语言的变量作用域没什么差别,不过在rust中,当变量s离开作用域,rust会为我们自动调用它的drop方法,String的实现者可以实现该方法来完成内存的释放。在rust中,内存在拥有它的变量离开作用域后就被自动释放

貌似不实现也会有drop方法

所有权移动

let str1 = String::from("hello");
let str2 = str1;
println!("{}", str1);

在大部分语言中,上面的代码都是将str1的引用赋值给str2,并不会造成堆上数据(字符串"hello")的拷贝。在rust中也是这样的,不过,rust的所有权规则有如下定义:

值在任意一刻有且只有一个所有者

所以,实际上,上面的代码实际上有一个错误,在第1行中,str1持有这个字符串值,在第2行中,这个字符串值的所有权转移到了str2上,所以,str1无效了。你尝试编译时会出现这样的错误,编译器告诉你值已经被转移了:

img

考虑如果rust允许str1str2同时持有该值,那么在作用域结束后,它会对这一个值drop两次。

rust的各种限制可以将所有(至少是大部分吧)内存错误在编译时被发现

下面的代码都不会出错,因为它们操作的都是字面量,和其它语言一样,字面量在赋值时是直接复制值的,而不是传递引用。这涉及到copy trait,稍后会说。

let str1 = "hello";
let str2 = str1;
println!("{}", str1);

let x = 1;
let y = x;
println!("{}", x);

克隆和拷贝

当你确实想对某一个对象进行值赋值时,而非引用赋值,即类似其它语言中拷贝的概念,你可以使用通用方法clone来实现克隆:

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

如上面所说,那些只在栈上存储的数据,比如i32、字符串字面量,对它们的传递本身就是使用拷贝的,如果一个类实现了copy trait,它们在进行赋值给其它变量时就会使用拷贝,也不会发生所有权移动,因为此时它们已经是两个值了

rust中实现copy trait的类型:

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

所有权与函数

注意,在调用函数时实际上也是做了一次隐含的赋值操作,这里也涉及到所有权移动。

fn take_ownership(some_string: String) { // 值的所有权移动到`some_string`变量上
    println!("{}", some_string);
} // 超出作用域,销毁`some_string`的值,drop被调用

fn main() {
    let s = String::from("Hello");  
    take_ownership(s); // 变量s的值发生所有权转移,它不属于s了
    println!("{}", s); // move occurs because `s` has type `String`, which does not implement the `Copy` trait
} // s不具有任何值的所有权,所以什么都不会发生

相同的,对于实现了copy trait的类型,赋值时进行一次拷贝,所以不影响拷贝前的值

fn main() {
    let x = 15;
    makes_copy(x);  // 发生值拷贝
    println!("{}", x); // correct because x implement copy trait
} // x被移除作用域,同时它是栈上值,直接无了

fn makes_copy(some_integer: i32) { // 值被拷贝了一份新的给some_integer
    println!("{}", some_integer);
} // some_integer被移除作用域,同时它是栈上值,直接无了

未完...

标签:rust,作用域,str1,let,内存,所有权,Rust
From: https://www.cnblogs.com/lilpig/p/16888542.html

相关文章

  • RUST包管理 模块系统讲解
    RUST包管理模块系统0一些基本概念package:包,cargonew生成的整个项目应该可以叫做包(我个人理解是这样的,至少package是最顶层的)一个package包含零个或一个库crate(lib......
  • rust基础学习
    rust基础学习rust环境配置rust在线工具:https://play.rust-lang.org/如果还没有安装C/C++编译环境,需要先进行安装(可以选择安装visualstudio)Rustup在Windows上是一个可......
  • 34 Must Know Terms for Embedded Rust Newbies
    https://apollolabsblog.hashnode.dev/34-must-know-terms-for-embedded-rust-newbies WhenIfirststartedoutinembeddedRustandengagedwiththecommunity,I......
  • Dataverse中跨业务部门的记录所有权
    1,先放连接​​https://learn.microsoft.com/zh-cn/power-platform/admin/wp-security-cds#matrix-data-access-structure-modernized-business-units​​需要通过管理画面开......
  • rust 基础 —— Option 的 as_ref 与 as_deref
    代码:fnhello(name:&String){println!("Nameis{}",name);}fngreet(name:&str){println!("Nameis{}",name);}fnmain(){letoption_name......
  • RUST
    Hello,World基础指令mkdir(新建目录)cd(进入文件夹)rustcxxxx.rs(关于该代码,创建一个可运行文件(二进制代码)。(rustc并不常用).\xxxx.exe(运行该文件)示例(HelloWor......
  • Rust语言学习
    参考Rust教程vim插件rust语言官网......
  • source insight 使用Uncrustify来格式化代码
    参考 ​​http://myswirl.blog.163.com/blog/static/5131864220106295590650/​​1.下载 ​​http://sourceforge.net/projects/uncrustify/​​,下载解压......
  • 012 Rust 异步编程,在 async 块中使用?
    在Rust异步编程中能否像在同步编程中一样使用问号呢?我们来试试。示例源码[dependencies]futures="0.3"配置文件usefutures;asyncfnfoo()->Result<(),String>{"f......
  • 013 Rust 异步编程,Send trait 相关
    asyncfnFuture是否为Send的取决于是否在.await点上保留非Send类型。编译器尽其所能地估计值在.await点上的保存时间。示例源码usestd::rc::Rc;#[derive(Default)]struct......