首页 > 其他分享 >写给rust初学者的教程(二):所有权、生命周期

写给rust初学者的教程(二):所有权、生命周期

时间:2024-03-15 17:33:07浏览次数:32  
标签:教程 self BigInteger len let 初学者 data rust vec

这系列RUST教程一共三篇。这是第二篇,介绍RUST语言的关键概念,主要是所有权和声明周期等。

第一篇:写给rust初学者的教程(一):枚举、特征、实现、模式匹配

在写第一篇中的练习代码时,不知道你有没有尝试过连续两次执行vec_min函数。这种做法在大部分其他语言中都属于正常行为,但如果你对rust这样做了,立即就得到一个error,编译都通不过:
image
“值在被移走后用掉了”!怎么会这样?

rust的宗旨是内存安全。为了实现这个任务,rust指定了一条铁律:通过别名访问数据时不能修改数据。这就是大名鼎鼎的“所有权”!

实际上这就是内存安全问题的根源:可变性以及起别名。可以看一下这些文章:Aliasing is what makes mutable types risky (Java), Aliasing and “Mutation at a Distance” (Python)

ownership

为什么要这样呢?我们通过一段C++程序来看这个问题:

  void foo(std::vector<int> v) {
      int *first = &v[0];
      v.push_back(42);
      *first = 1337;
  }

传统程序里面,C++的内存需要我们程序员来管理。这里变量first指向了参数v的首地址,然后给这个数组插入一个新元素;如果插入的时候数组是满的,v就会指向一个新的更大的数组,这样first指向的内存实际是无效的了。这就是超名昭著的“悬垂指针”问题。
那rust怎么做的呢?
看一个小程序:

    fn handle_vector(v: Vec<i32>) {  }
    fn ownership_test() {
        let v = vec![1,2,3,4];
        handle_vector(v);
        println!("{}", v[0]);
    }

肉眼看这个程序好像非常正常,但是给cargo build瞅了一眼,它说最后一句有问题,编译不了! Son of a biscuit.
rust中,当你把一个变量传到其他函数中时,rust认为你主动出让了所有权,出让后你就再也不能访问这个变量了。在其他函数执行完成后,这个传进去的变量处的内存会被回收掉。如果允许你访问,就和上面说的“悬垂指针”一样的问题了。
那这和上面说的所有权规则有啥关系?所有权规则是:通过其他别名访问数据时不可修改。可是传给其他函数后(必然会起别名),数据可能被修改了,所以你就不能再访问了。

可是Java里面就是这样传进去的啊!也没出问题啊

rust也能实现Java这样的效果。——当然能,必须能;如果不能,我相信没人会使用rust了。
还是以我们的vec_min函数为例,来看一下rust中的引用“借用”。

&

目前的函数签名是这样的:

    fn vec_min<T: Minimum>(vec: Vec<T>) -> SomethingOrNothing<T> {}

假设你有一部iPad,你的朋友们都可以借用它来浏览网页,用完还给你,期间他的朋友可能也会借用一会;但是他们借走期间,你没法使用它了 —— 当然是这样,毕竟我们也遵循“泡利不相容原理”,噗。
rust也模仿的这种现实:传递参数时可以指明是在“borrowing”而非“moving”。之前我们写的代码都是对所有权进行了move,要改成borrow需要在参数类型前面增加一个&

fn vec_min<T: Minimum>(vec: &Vec<T>) -> SomethingOrNothing<T> {}

现在vec不再是集合类型了,而是&Vec类型。要想拿到引用对应的变量值,需要使用解引用符号*

    fn vec_min<T: Minimum>(vec: &Vec<T>) -> SomethingOrNothing<T> {
        let mut min = Nothing;

        for e in vec {
            min = Something(match min {
                Something(i) => { e.compare(i) }
                Nothing => { *e }
            })
        }

        min
    }   

这里还涉及两处其他的改动:

  1. 你可以通过观察或者运行来发现,为什么e是一个引用类型,但是只有Nothing的分支进行了解引用,Something分支却直接调用了它的compare方法。所以这里需要去修改comapre方法,将第一个参数self改成&self
    pub trait Minimum : Copy {
        fn compare(&self, s: Self) -> Self;
    }

    impl Minimum for i32 {
        fn compare(&self, s: Self) -> Self {
            if *self < s { *self } else { s }
        }
    }

相应的,实现的地方在返回的时候也要判断,返回self就使用*self,返回s则不用加*

  1. 第二个问题比较难发现,需要给元素类型实现Copy特征,上面代码中已经增加了。

现在你可以试一下了,调用两次vec_min并不会报错了。

&mut

借出去的所有权,数据可以被修改吗?
是可以的。
你可以尝试在vec_min中给参数中push或者remove。应该会报错,根据错误信息响应的调整代码即可。你会发现,参数类型前面也可以加mut,变成了这样:

fn vec_min<T: Minimum>(vec: &mut Vec<T>) -> SomethingOrNothing<T> {}

甚至这样写:

    for e in v.iter_mut() {
        *e += 1;
    }

但是由于是引用类型,并不能赋值。你可以在调用前多次vec = vec![2];vec = vec![3];,但是在vec_min里面却不能执行这样的语句。

借用引用和可变引用

上面说的实际是两种不同的引用类型。rust中严格区分了他们。跟编程中的加锁一样,借用引用(用&来开启)同一时刻是可以存在多个的,他们互相不影响,因为只有读操作 —— 就和读锁一样;而可变引用(用&mut开启)同一时刻只能存在一个,而且使用了可变引用就不能使用借用引用了,因为什么?“不可重复读”。所以可变引用就是排它锁,可以称为 唯一引用


再来一个例子。
这次我们构造一个对象,类似于Java中的BigInteger。这种对象能够表示非常大的数,内存有多大数就有多大(哈哈

标签:教程,self,BigInteger,len,let,初学者,data,rust,vec
From: https://www.cnblogs.com/somefuture/p/18046979

相关文章

  • Python之Web开发中级教程----创建Django子应用
    Python之Web开发中级教程----创建Django子应用基于上一个教程的Django项目(可以先看上一集,链接如下:)https://mp.csdn.net/mp_blog/creation/editor/1367248972.创建子应用pythonmanager.pystartappbookadmin.py:跟网站的后台管理站点配置相关。apps.py:用于配置当前应用......
  • gdb调试工具使用教程
    编译的时候必须带-g才会有调试信息常用的命令l=list主函数源码列出多行的办法,默认是十行,两个参数用逗号隔开,前面是开始,后面是终止行b=breakpoint设置断点后面跟数字行数,b6,代表第六行设置断点,infob可以看到所有断点的设置情况,可以用delete删除断点r=run全......
  • 国产Ai代码助手,通义灵码IDEA安装教程
    访问链接注册《通义灵码》账号https://developer.aliyun.com/topic/lingma/activities/202403?taskCode=14508&recordId=7b0c66673d3e0e56e7e970d788cfc465#/?utm_content=m_fission_1 步骤1点击File-->Settings步骤2点击Plugins-->Marketplace步骤3搜索通义灵码(TONG......
  • 【干货】Onlyfans注册订阅手把手教程
    前言本文来教大家如何注册OnlyFans,并且如何通过支付宝(ps:是使用支付宝购买虚拟卡来实现)订阅和支付 OnlyFans ,并且提供年龄验证等问题解决方案一、OnlyFans介绍OnlyFans是一个允许创作者分享自己的独家内容的平台,简称o站。这个平台允许创作者创建一个订阅服务,粉丝需要支付......
  • Npm使用教程
    简介npm,全名nodepackagemanger,是node的开放式模块登记和管理系统,是node.js包的标准发布平台。npm如何使用npm在按照Node.js时会连带被安装。但有可能不是最新版本,需要npminstallnpm@latest-g升级到最新版本。基本命令:#查看npm命令列表$npmhelp#查看各个......
  • 【数据挖掘】实验1:R入门(内含详细R和RStudio安装教程)
    实验1:R入门一:实验目的与要求1:根据上课PPT内容,掌握课堂知识并进行代码练习操作,提供练习过程和结果。2:可COPY代码运行结果直接提交,如涉及到输出图等可截图。二:实验内容1:R语言的下载与安装1.1:安装R语言从清华镜像网站(TheComprehensiveRArchiveNetwork)处下载Windows版......
  • aardio教程一) 基础语法-上
    前言想开发一些小工具,所以想系统性的学习一遍aardio,之前都是哪里不会搜哪里,顺便写些教程。我的主要语言是Python,所以会以Python作为对比来加深印象。aardio的基础语法和JavaScript基本类似,如果你学过JavaScript,aardio很容易上手。下面的文档来自官方文档[1]问题搜索途径基础......
  • 【rust】《处理报错Cannot find a libtorch install, you can either:》
    在学习rust的tch-rs框架的时候,引入依赖并运行小demo的时候报错了;错误信息如下:报错信息Cannotfindalibtorchinstall,youcaneither:-InstalllibtorchmanuallyandsettheLIBTORCHenvironmentvariabletoappropriatepath.-Useasystemwideinstallin/us......
  • 想学一门技术或者搞副业,学什么最靠谱?当然是Python!清华教授35天python教程脑图,让你学习
    想学一门技术或者搞副业,学什么最靠谱?派森君告诉你:当然是Python。为什么呢?Python语言是所有语言中最好上手的语言,简单易学。只要是懂一点英语,逻辑思维不是很差的人很快就能学会。一方面Python作为一门全场景编程语言,当前的应用边界在不断扩展,相信随着大数据、人工智能等技......
  • 2024最新整理Python入门教程(超详细),从零基础入门到精通,看完这一篇就够了
    前言本文罗列了Python零基础入门到精通的详细教程,内容均以知识目录的形式展开。01.python由来与发展介绍02.项目开发流程【文末有惊喜福利......