首页 > 其他分享 >所有权

所有权

时间:2024-09-25 10:03:56浏览次数:1  
标签:String 作用域 s2 s1 let 所有权 hello

所有权

所有权是Rust独有的特性,它让Rust无需GC就可以保证内存安全。

所有权解决的问题

Stack-栈

压入(把值压入stack不叫分配)
stack存放的是固定大小的数据。
应为指针是已知固定大小的,可以把指针存放到stack上。
把数据压入stack比在heap上分配快的多。

Heap-堆

分配
跟踪代码那些部分正在使用heap的那些数据。
最小化heap上的重复数据。
清理heap上未使用的数据,以免空间不足。
管理heap数据才是所有权存在的特性。

所有权规则

  • 每一个值都有一个变量,这个变量是该值的所有者。
  • 每个值同时只能有一个所有者(变量)。
  • 当所有者(变量)超出作用域(scope)时,该值将被删除(drop)。

作用域

fn main() {
    {    // s 在这里无效,它尚未声明
        let s = "hello";  // 从此处起,s 是有效的

        // 使用 s
        println!("s is {}", s);
    }   // 此作用域已结束,s不再有效
} 

变量和数据交换方式

移动

基本数据类型

x、y已知固定大小的简单值,都会被压到stack中

stateDiagram Stack栈 state Stack栈 { [*] --> y=5 : <font color=#32CD32>new</font> y=5 --> x=5 x=5 --> [*] }
let x = 5;
let y = x;

复杂数据类型

Alt text
s2只复制了s1在stack上的指针信息,并没有复制heap上数据。
并且上s1废弃,当s1离开作用域时不需要释放任何东西。
如果s1没有被废弃,那么当s1,s2离开作用域时,会释放两次heap内容,内存不安全。

浅拷贝和深拷贝,Rus复制了指针、长度、容量视为浅拷贝,但是会把原先的变量失效了,所以叫做移动

stateDiagram direction LR Stack栈 Heap堆 s1变量 --> hello字符串 : <font color=FF0000>1.失去所有权</font> s2变量 --> hello字符串 : <font color=#32CD32>2.获取所有权</font> state Stack栈{ s1变量 s2变量 } state Heap堆{ hello字符串 }
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // 所有权发生了转移,s1不再有效
    // println!("s1 = {}", s1) // 如果接着打印会报错
    println!("s2 = {}", s2);
} 

克隆

2s把s1的heap上的数据clone了一份

stateDiagram-v2 direction LR Stack栈 Heap堆 s1变量 --> hello字符串 s2变量 --> hello字符串' : <font color=#32CD32>复制s1在heap的内容</font> state Stack栈{ s1变量 s2变量 } state Heap堆{ hello字符串 hello字符串' }
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}", s1);
    println!("s2 = {}", s2);
}

拷贝

1.Copy trait通常用于像整型等存储在栈上的类型。
2.如果一个类型实现了Copy trait,在赋值给其他变量后,旧的变量仍然可用,即发生按位复制而不是所有权转移。
3.一个类型实现了Drop trait, 那么不允许实现Copy trait,因为这类类型在值离开作用域时需要特殊处理。

以下类型实现了 Copy trait

  • 所有整数类型,比如 u32。
  • 布尔类型,bool,它的值是 true 和 false。
  • 所有浮点数类型,比如 f64。
  • 字符类型,char。
  • 元组,当且仅当其包含的类型也都实现 Copy 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。
fn main() {
    let x = 5;
    let y = x;
    println!("x = {}, y = {}", x, y);
} 

所有权与函数

fn main() {
    let s = String::from("hello"); // s 进入作用域
  
    takes_ownership(s); // s 的值移动到函数里 ...
    // println!("s: {}", s); 所以到这里s就失效了,如果打印的话就报错了

    let x = 5; // x 进入作用域

    makes_copy(x); // x 应该移动函数里,
    // 但 i32 是 Copy 的,所以在后面可继续使用 x

    println!("x: {}", x);
  
} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,所以不会有特殊操作

fn takes_ownership(some_string: String) { // some_string 进入作用域
    println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
    println!("{}", some_integer);
} // 这里,some_integer 移出作用域。不会有特殊操作

返回值与作用域

fn main() {
  let s1 = gives_ownership();         // gives_ownership 将返回值
                                      // 移给 s1

  let s2 = String::from("hello");     // s2 进入作用域

  let s3 = takes_and_gives_back(s2);  // s2 被移动到
                                      // takes_and_gives_back 中,
                                      // 它也将返回值移给 s3
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,
  // 所以什么也不会发生。s1 移出作用域并被丢弃

fn gives_ownership() -> String {           // gives_ownership 将返回值移动给
                                           // 调用它的函数

  let some_string = String::from("yours"); // some_string 进入作用域

  some_string                              // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域

  a_string  // 返回 a_string 并移出给调用的函数
}

转移返回值的所有权

在每一个函数中都获取所有权并接着返回所有权有些啰嗦。
所以Rust对此提供了一个功能,叫做引用

fn main() {
    let s1 = String::from("hello");

    let (s2, len) = calculate_length(s1);

    println!("The length of '{}' is {}.", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len(); // len() 返回字符串的长度
    // 每次都需要返回所有权,麻烦
    (s, length)
}

标签:String,作用域,s2,s1,let,所有权,hello
From: https://www.cnblogs.com/lxd670/p/18411892

相关文章

  • 万象更新 Html5 - h5: h5 通过 web worker 实现多线程(演示如何转移数据的所有权)
    源码https://github.com/webabcd/Html5作者webabcd万象更新Html5-h5:h5通过webworker实现多线程(演示如何转移数据的所有权)示例如下:h5\webWorker\worker_transferable.html<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"&......
  • Rust 所有权 Slices
    文章目录发现宝藏1.Slice的基础知识1.1什么是Slice?1.2如何创建Slice?2.处理字符串Slice2.1字符串的Slice2.2字符串的Unicode和切片3.在函数中使用Slice3.1传递Slice给函数3.2可变Slice的函数4.复杂示例4.1处理多维数组的Slice4.2使用slice......
  • rust语言之所有权
    Rust受现代c++的启发,引入智能指针来管理堆内存。在rust中,所有权是系统性的概念,是rust语言的基础设施。5.1通用概念编程语言中的值主要分成两类:值类型(Value):数据直接存储在栈中的数据类型引用类型(Reference):将数据存在堆中,而栈中值存放指向堆中数据的地址(指针)为了更精确的对......
  • mysql 给了用户所有权限ALL PRIVILEGES,但是该用户没有grant权限
    在MySQL中,给用户ALLPRIVILEGES权限但没有grant权限的情况可能是因为MySQL版本的更新导致了语法的变化。在MySQL8.0及更高版本中,GRANTALLPRIVILEGES的用法已经不再支持,需要使用GRANTALLPRIVILEGESON*.*TO'username'@'host'WITHGRANTOPTION;的格式来授予用户全局权限和......
  • Rust——所有权
    前言所有权是Rust最独特的特性,对语言的其余部分有着深远的影响。它使Rust能够在不需要垃圾收集器的情况下保证内存安全,因此了解所有权的运作方式非常重要。在本章中,我们将讨论所有权以及几个相关功能:借用、切片以及Rust如何在内存中布局数据。内容什么是所有权所有权是......
  • 深入浅出Rust所有权:手把手从零设计Rust所有权体系,掌握Rust内存管理思想的精髓
    撰写编程语言发展历史过程中,对Rust的所有权机制的设计进行了深入的探讨,摘取其中的一段内容,邀请大家点评。Rust的所有权机制,看似复杂且与现有编程语言不同,使用起来思路也许难以适应。是学习Rust的难点。但如果我们换个思路,假设我们是Rust的设计者,逐步深入Rust的内心世界,也许......
  • Rust所有权__Ownership Rules
    First,let’stakealookattheownershiprules.Keeptheserulesinmindaswethroughtheexamplesthatillustratethem:     EachvalueinRusthasanowner.     Therecanonlybeoneowneratatime.     Whentheownergoesoutofsc......
  • Rust所有权__Ownership
    OwnershipisasetofrulesthatgovernhowaRustprogrammanagesmemory.Allprogramshavetomanagethewaytheyuseacomputer'smemorywhileruning.Somelanguageshave garbagecollectionthatregularlylooksforno-longer-usedmemoryasthepro......
  • 转移线程所有权
    假设要写一个在后台启动线程的函数,想通过新线程返回的所有权去调用这个函数,而不是等待线程结束再去调用;或完全与之相反的想法:创建一个线程,并在函数中转移所有权,都必须要等待线程结束。总之,新线程的所有权都需要转移。这就是移动引入std::thread的原因。C++标准库中有很......
  • 写给rust初学者的教程(二):所有权、生命周期
    这系列RUST教程一共三篇。这是第二篇,介绍RUST语言的关键概念,主要是所有权和声明周期等。第一篇:写给rust初学者的教程(一):枚举、特征、实现、模式匹配在写第一篇中的练习代码时,不知道你有没有尝试过连续两次执行vec_min函数。这种做法在大部分其他语言中都属于正常行为,但如果你对......