文档章节

rust04所有权

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:17
字数 1408
阅读 2
收藏 0
点赞 0
评论 0

所有权指涵盖的范围有: 变量作用域、垃圾处理机制、引用,围绕着几种行为来阐述所有权概念。

 

变量作用域(Scope)

任何编程语言中都存在变量作用域的概念, Rust中的变量作用域与其他编程语言也基本一致;作用域大致上会分为: 全局作用域, 函数内作用域.

全局作用域

在下面这段代码中, PROGRAM常量和main函数就是一个全局作用域; 反过来讲就是当前程序代码中,全局作用域拥有两个对象, 第一个对象是 PROGRAM 常量, 第二个对象是 main 函数。

const PROGRAM: &'static str = "Rust";

fn main() {
    println!("{}", PROGRAM);
}


# 作用域的形式可以这么理解, global_scope中有两个对象.
global_scope = {
    "const PROGRAM": "Rust"
    "fn main": "println!({}, PROGRAM)"
}
函数内作用域

变量不能let(定义)在全局作用域中, 所以全局作用域能做的事情并不多: 定义常量、定义函数、引用其他模块文件; 更多的合法操作实在函数作用域中完成: 定义变量、打印变量、逻辑计算、逻辑判断、函数调用和执行等.

const PROGRAM: &'static str = "Rust";

fn main() {
    let s = "abc";                      // 定义变量
    let sf = simple_function();         // 执行函数
    let sum = 10 + 15;                  // 逻辑计算
    if sum > 0 {                        // 逻辑判断
        println!("{} {} {}", PROGRAM, s, sum);  // 打印常量和变量
    }
}

fn simple_function() {
    let sf = "Simple Function";         // 定义变量
    sf                                  // return 变量
}


# 作用域的形式可以这么理解, global_scope中有三个对象, 其中
# main对象中又有一个二级作用域, simple_function对象中也有一个
# 二级作用域.
global_scope = {                        // 作用域

    "const PROGRAM": "Rust",

    "main": {                           // 作用域
        "let s": "abc",
        "let sf": "Simple Function",
        "let sum": 25,
    },

    "simple_function": {                // 作用域
        "let sf": "Simple Function"
    }
}

 
 

垃圾处理机制

像其他具备GC回收机制编程语言一样,当程序执行完成并跳出某个作用域(通常指的是一个函数)时,该作用域中的所有变量将会失效(被回收);除此之外, Rust对垃圾回收这件事情上还具备其他的能力和行为, 例如: 当需要对存储在堆(Heap)中的数据进行复制时, 被赋值对象将具备赋值对象的数据,而赋值对象将会被回收。

离开作用域时回收数据
fn simple_function() {
    let sf = "Simple Function";    // sf变量开始生效
    println!("{}", sf);            // sf变量仍然生效
}                                  // sf变量不再生效

fn main() {
    simple_function();             // 当该函数执行完成后, sf变量就会被回收
    println!("{}", sf);            // 报错: sf变量不存在.
}
变量传递后即刻失效
fn simple_function(sf: String) {
    println!("simple_function: {}", sf);
}

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



# 报错
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0382]: use of moved value: `s`
  --> src/main.rs:10:26
   |
9  |     simple_function(s);
   |                     - value moved here
10 |     println!("main: {}", s);
   |                          ^ value used here after move
   |
   = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
通过return让它重回原作用域
fn simple_function(sf: String) -> String {  // -> String 声明返回值类型
    println!("simple_function: {}", sf);
    sf
}

fn main() {
    let s = String::from("hello");
    let s = simple_function(s);     // 利用返回值, 重新定义变量.
    println!("main: {:?}", s)       
}
数据存储在栈上时, 变量再赋值不会回收原变量
fn main() {
    let a = 10;                 // rust会将固定不变的值存储在栈(Stack)上.
    let b = a;                  // rust对栈上的数据默认采取深复制.
    println!("{} {}", a, b);
}

fn main() {
    let a = "abc";              // 与上面是一样的.
    let b = a;                  
    println!("{} {}", a, b);
}
当变量存储再堆上时, 变量再赋值就会回收原变量(所有权转移)
fn main() {

    // rust会将这种未知大小的数据存储在堆(Heap)上.
    // 因为String::from这种结构的数据支持push_str
    // 来扩充它的大小, 因此从本质上来讲是未知大小.
    let a = String::from("hello");  

    // rust对堆上的数据默认采取移除上一个变量创建
    // 新变量的机制, 这种做法在术语上叫做所有权转移.
    let b = a;                  

    // 这里会报错, a变量已被移除
    println!("{} {}", a, b)     
}


# 报错信息
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0382]: use of moved value: `a`
  --> src/main.rs:10:23
   |
7  |     let b = a;
   |         - value moved here
...
10 |     println!("{} {}", a, b)
   |                       ^ value used here after move
   |
   = note: move occurs because `a` has type `std::string::String`, which does not implement the `Copy` trait

 
 

引用(reference)

不可变更引用(默认)
fn main() {
    let a = 10;

    // b变量是一个指针, 它并没有实际数据的所有权.
    let b = &a;

    // 引用是在栈上创建一个指针指向栈数据.
    // 它比在栈上深复制更轻量.
    println!("{} {}", a, b)     
}
可变引用
fn main() {
    let mut a = "hello";
    a + "b"
    println!("{}", a)
}
引用的注意事项
可变对象不能被多次引用, 这会导致数据竞争.
fn main() {
    let mut a = 10;
    let b = &mut a;
    let c = &mut a;
}


# 报错
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0499]: cannot borrow `a` as mutable more than once at a time
  --> src/main.rs:18:18
   |
17 |     let b = &mut a;
   |                  - first mutable borrow occurs here
18 |     let c = &mut a;
   |                  ^ second mutable borrow occurs here
19 | }
可变对象被可变引用之后, 再次引用会导致数据不一致.
fn main() {
    let mut a = 10;

    // 可变对象被可变引用走了
    let b = &mut a;

    // 这里会报错, 因为数据状态任何时刻都可能会改变,
    // 这是不可预期的, 所以rust不允许这种情况的出现.
    println!("{} {}", a, b)
}
可变对象被可变引用之后,数据不一致的解决办法
fn simple_function(sf: &mut String) -> String {
    sf.push_str(" world!");
    let new_sf = sf.clone();
    new_sf
}

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

    // 站在变量的角度来讲: &mut a 的专业术语为<可变引用>
    // &mut a 当做参数传递给函数时, 专业术语为<可变借用>
    let b = simple_function(&mut a);  

    println!("a: {}\nb: {}", a, b)
}

本文转载自:http://www.jianshu.com/p/87f983c840a4

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2634
码字总数 82983
作品 0
程序员
ARC中__bridge, __bridge__transfer, __bridge_retaine

多数情况下,Objective-C 对象和 Core Foundation 对象之间互相转换时, 我们都应该使用bridge。但是有时候我们确实需要给予 ARC 某个对象的所有权, 或者解除 ARC 对某个对象的所有权。这种情况...

lingfeng72
2015/11/24
24
0
对BOOST 中同步互斥的一些理解

对BOOST 中同步互斥的一些理解 首先,BOOST中有4种有关互斥量得概念。 1.LOCKABLE :仅支持排它型所有权 2.TIMEDLOCKABLE:支持带超时的排它型所有权 3.SHAREDLOCKABLE: 支持带超时的排他型所...

江浸月
2013/02/18
0
1
chgrp - 改变文件的组所有权

NAME chgrp - 改变文件的组所有权 总览 chgrp [选项] 组文件... POSIX 选项: [-R] [--] Austin 草拟选项: [-hHLPR] GNU 团体指示: [--reference=rfile] GNU 选项 (简易格式): [-cfvR] [--hel...

zhongyilin
2014/03/04
0
0
使用命令chown改变文件、目录的所有权;使用chgrp命令修改文件、目录的组;

使用命令chown改变文件、目录的所有权 超级用户root 或者具有超级用户身份的用户(这里系统的所有者nling 就是一个超级用户),有权利修改文件/目录的所有权,这是Linux 系统所必须确定的。超...

DavidBao
2015/05/18
0
0
《从零开始学Swift》学习笔记(Day 61)——Core Foundation框架之内存管理

原创文章,欢迎转载。转载请注明:关东升的博客 在Swift原生数据类型、Foundation框架数据类型和Core Foundation框架数据类型之间转换过程中,虽然是大部分是可以零开销桥接,零开销并不意味...

智捷课堂
2016/01/18
31
0
《从零开始学Swift》学习笔记(Day 62)——Core Foundation框架之内存托管对象

原创文章,欢迎转载。转载请注明:关东升的博客 内存托管对象 Swift中调用Core Foundation函数获得对象时候,对象分为:内存托管对象和内存非托管对象。 内存托管对象就是由编译器帮助管理内...

智捷课堂
2016/01/20
32
0
vmware提示:此虚拟机似乎正在使用中,无法取得所有权的解决办法

在虚拟机运行时,一次非正常关机。导致虚拟机出现以下错误: 此虚拟机似乎正在使用中。 如果此虚拟机已在使用中,请按“取消”按钮,以免损坏它。如果此虚拟机未使用,请按“取得所有权(&T)”...

Junn
2014/06/16
0
3
oc的内存管理机制.及自动释放池的解析

一.内存管理的方式 MRC 人工引用计数:内存的开辟和释放由程序代码无师自通控制,() ARC 自动引用计数(不是自动内存管理)(编译器帮助程序员默认加了释放代码) 在C中使用malloc和free oc中内存管...

Dolion-Hou
2016/03/20
127
0
C++11 FAQ中文版:unique_ptr

二27Year 2011陈 良乔C++11 FAQ unique_ptr uniqueptr(定义在中)提供了一种严格的语义上的所有权 o 拥有它所指向的对象 o 无法进行复制构造,也无法进行复制赋值操作(译注:也就是对其无法...

长平狐
2013/01/11
89
0
教你取得计算机的所有权(可删除和打开或复制系统文件)

很简单,先新建一个文本文档,然后将以下代码复制进去: -------------------分割线----------------------- Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOTshellrunas] @="取得所...

吴小编
2013/12/25
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

zk实战--rpc框架集群化

在看此篇内容时需要浏览下面内容 netty实战--手写rpc框架 前文功能简介以及功能扩充 利用netty来实现一个点对点的rpc调用。客户端和服务端都是靠手写地址进行socket同学的,无法1对多,也无法...

xpbob
12分钟前
7
0
springboot 发送邮件

获取授权码 添加配置 # 账号和密码spring.mail.username=aaa@qq.comspring.mail.password=bbb# 服务器地址spring.mail.host=smtp.qq.comspring.mail.properties.mail.smtp.ssl.en...

阿豪boy
13分钟前
0
0
如何使用GNU Ring?

文章名:如何使用GNU Ring? 作者:冰焰火灵X 1079092922@qq.com 文章许可:CC BY-SA 4.0 ##1. 安装 下载GNU Ring 点击左边选择你的系统版本(这里以 GNU/Linux 为例,我使用的是Mint 18.3)...

ICE冰焰火灵X
15分钟前
1
0
深入理解springMVC

什么是spring MVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而...

Java填坑之路
21分钟前
1
0
《射雕英雄传》书摘

1. 我虽是个飘泊江湖的贫家女子,可不是低三下四、不知自爱之人。你如真心爱我,须当敬我重我。我此生决无别念,就是钢刀架颈,也决意跟定了你。将来……将来如有洞房花烛之日,自然……自能...

k91191
32分钟前
0
0
解决:modal中datePicker 选中时,会触发modal的hidden.bs.modal事件

最近项目中发现了一个bug,具体表现为选中模态框上datepicker组件上的日期时,会触发模态框的关闭事件,导致数据编辑无法正常进行。网上搜索了下,解决方法如下: $('.datepicker').on('hid...

Funcy1122
35分钟前
0
0
Redis分布式锁的正确实现方式

前言 分布式锁一般有三种实现方式: 1.数据库乐观锁 2.基于Redis的分布式锁; 3.基于Zookeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis...

大海201506
今天
0
0
ClassNotFoundException: javax.el.ELManager

这个是因为tomcat7中的el-api2.2,有些版本太低,建议升级tomcat到8.0,利用el-api3.0就会解决这个问题。

无语年华
今天
0
0
Jvm堆内存的划分结构和优化,垃圾回收详解(详细解答篇)

在JVM中堆空间划分如下图所示 上图中,刻画了Java程序运行时的堆空间,可以简述成如下2条 1.JVM中堆空间可以分成三个大区,新生代、老年代、永久代 2.新生代可以划分为三个区,Eden区,两个幸...

嘻哈开发者
今天
1
0
CentOS 7.4 设置系统字符编码

1.语言变量LANG在 /etc/locale 文件中。 2.可以通过/ect/profile 来修改LC_TYPE 变量的值 添加如下代码 export LC_ALL="zh_CN.GBK" export LANG="zh_CN.GBK" 到profile文件中,变量的可以修改...

qimh
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部