变量的声明和定义

Rust中合法的标识符(包括变量名、函数名、triat名等)必须由数字、字母、下划线组成,而且不能以数字开头。这个和很多语言都是一样的。Rust将来也会允许其他Unicode字符作为标识符,还有raw identifier功能,这样可以使关键字作为标识符,比如r#self,这个用途在FFI中最多。

变量的声明: let variable : i32 = 100; , 在rust中采用的变量的声明方式不同于以往语言的声明方式,这里先看变量的声明, 变量的声明时,是变量的名字先在前,而变量的类型在后面,let variable: i32;就是这个样子。

这样变量声明的好处是,对于语法分析来说分析更为方便,并且在变量声明语句中最为重要的是变量的名字,将变量名提前突出显式变量名的重要性,对于类型是变量名的附加说明,可以通过上下文推导出变量的类型,当让rust的自动类型推导具有局限性,对于不能推导出来的类型,需要手动添加类型说明。

变量声明中的let的使用也是借鉴了函数式语言的思想,let表明的是绑定的含义,表示的是将变量名和内存作了一层绑定关系。在Rust中,一般把声明的局部变量并初始化的语句称为”变量绑定“, 这里强调的是”绑定“的含义,这里和C++/C中的”赋值初始化语句有所不同。

变量定义的一些问题

Rust中,每个变量必须被合理初始化之后才能被使用,使用未初始化变量这样的错误,在rust中是不可能出现的。

检查是否声明初始化变量

刚刚上面的let variable : i32;这个是声明,而没有给变量赋值,这个在别的语言中可能是行的通的,但是在rust中,编译器直接报错(如果在后面使用这个为赋值(定义)的变量, Rust编译器会对代码作基本的静态分支流程分析,确保变量在使用之前一定被初始化,variable没有绑定任何值,这样的代码会引起很多内存不安全的问题,比如计算结果非预期、程序崩溃,所以Rust编译器必须报错。

1 let variable: i32;
2 println!("variable = {}", variable); // error[E0381]: use of possibly unintialized 'variable'

检测分支流程是否产生为初始化变量

Rust编译器的静态分支流程分析比较严格。

1 fn main() {
2 let x: i32;
3 if true {
4 x = 1;
5 } else {
6 x = 2;
7 }
8 println!("x = {}", x);
9 }

这里的if分支的所有情况都给变量x绑定了值,所以它可以运行。但是如果去掉else分支,编译器就会报错:

error: use of possibly unintialized variable : 'x'
println!("x = {}", x);

从这里可以看到编译器已经检查出来变量x没有被正确的初始化。去掉else分支后,编译器的静态分支流程分析判断出在if表达式之外的println!也用到了变量x,但并未有绑定任何值得行为。编译器的静态分支流程分析并不能识别if表达式中的条件是true, 所以他要检查所有分支的情况。(这个在程序设计语言领域中有专门去做研究的,比如软件的静态分析,一些参考材料:南京大学的软件分析课程)

要是在把println!语句也去掉的话,则可以正常编译运行,这是因为if表达式之外再也没有任何地方使用变量x, 在唯一使用到x的if表达式中已经绑定了值,所以编译正常。

 1 // 有一个例子
2 fn test(condition: bool ){
3 let x: i32; //声明x
4 if condition {
5 x = 1; //初始化x,这里是初始化
6 println!("{}", x);
7 }
8 // 如果条件不满足,x没有被初始化
9
10 //但是没有关系,只要这里不使用x就没有事
11 }

检测循环中是否产生未初始化变量

当循环中使用break关键字的时候,break会将分支中的变量值返回。

 1 fn main() {
2 let x : i32;
3 loop {
4 if true {
5 x = 2;
6 break;
7 }
8 }
9 println!("{}", x);// 2
10 }

Rust编译器的静态分支流程分析知道,break会将x的值返回,这样loop循环之外println!可以正常打印x的值

空数组或向量可以初始化变量

当变量绑定空的数组或向量时,需要显式制定类型,否则编译器无法推断其类型。

1 fn main() {
2 let a: Vec<i32> = vec![];
3 let b: [i32; 0] = [];
4 }

要是不加显式类型标注的话,编译器就会报错: error[e0282]: type annotation needed 空数组或向量可以用来初始化变量,但目前暂时无法用于初始化常量或静态变量。

转移了所有权产生了未初始化变量

当将一个已经初始化的变量y绑定给另外一个变量y2时,Rust会把y看做逻辑上的未初始化变量。 这里的y和y2都是移动语义的变量,移动语义的变量会发生所有权的交接,而值语义,就像其他C++语言默认的都是传值。

 1 fn main() {
2 let x = 42; //原生类型都是值语义,默认存储在栈上,
3 let y = Box::new(4); //变量是由Box装箱到堆上的, Box::new方法在堆上分配内存返回指针
4 //并与y绑定,而指针y存储在栈上,
5 println!("{}", y);
6 let x2 = x;
7 let y2 = y;
8 //println!("{}", y);//发生了所有权的转移,所以这里的变量y可以看做没有未被初始化的变量
9 //但是如果重新给变量绑定上一个值,变量y依然是可用的,这个过程叫做重新初始化
10 }

Rust中的变量的声明和定义的更多相关文章

  1. 【转】变量的声明和定义,从C到编译原理到C++,再到Java

    基础学了太久,时间一长有些东西就可能记得不太清楚,俗话说得好,"好记性不如烂笔头",所以把基础中的基础-变量的声明和定义,从C到编译原理到C++,再到Java用烂笔头记录下来 最早 ...

  2. 变量的声明和定义以及extern的用法

    变量的声明和定义以及extern的用法                                          变量的声明不同于变量的定义,这一点往往容易让人混淆. l         变量 ...

  3. JAVA学习笔记:注释、变量的声明和定义、

    本文内容: 注释 变量的声明和定义 成员变量和局部变量 首发时间:2018-03-16 15:59 注释: 单行注释:// 多行注释:/* - */ 变量: 变量是内存中的一个存储区域,变量的定义就是 ...

  4. C#中对于变量的声明和初始化

    C#变量初始化是C#强调安全性的另一个例子.简单地说,C#编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量.大多数现代编译器把没有初始化标记为警告,但C#编译器把它当作错误来看待. ...

  5. AJPFX总结面向对象中成员变量和成员方法的定义

    //面向对象中成员变量和成员方法的定义格式:=========================================          成员变量定义在类中方法外,可以被该类中所有方法使用. ...

  6. 【C++】C++中变量的声明与定义的区别

    声明(declaration):意味着告诉编译器关于变量名称.变量类型.变量大小.函数名称.结构名称.大小等等信息,并且在声明阶段不会给变量分配任何的内存. 定义(definition):定义就是在变 ...

  7. c++类模板中静态成员变量的声明定义

    我们知道,c++中,类的静态成员是要在.cpp文件中定义的,如果在.h中定义,会出现重复定义. 但是在写类模板时,一般所有的代码都是放在.h文件中的,如果要做分离是一件很麻烦的事.那如果出现了静态成员 ...

  8. C++ 变量的声明与定义的区别

    变量声明和定义的区别 我们在程序设计中,时时刻刻都用到变量的定义和变量的声明,可有些时候我们对这个概念不是很清楚,知道它是怎么用,但却不知是怎么一会事,下面我就简单的把他们的区别介绍如下:(望我的指点 ...

  9. java中static变量的声明和初始化

     目录(?)[+] 问题1静态变量如何初始化 问题2JDK如何处理static块 问题3如何看待静态变量的声明 对初始问题的解答 在网上看到了下面的一段代码: public class Test  ...

  10. Java变量常量声明和定义

    一.常量和变量 1.常量变量定义 在程序中存在大量的数据来代表程序的状态,其中有些数据在程序的运行过程中值会发生改变,有些数据在程序运行过程中值不能发生改变,这些数据在程序中分别被叫做变量和常量. 2 ...

随机推荐

  1. rocketMq和kafka对比

    为什么在RocketMQ和kafka中选型 在单机同步发送的场景下,Kafka>RocketMQ,Kafka的吞吐量高达17.3w/s,RocketMQ吞吐量在11.6w/s. kafka高性能 ...

  2. vue中 computed和watch的一些简单理解(区别)

    今天看到一个问题,就是vue的computed和watch要在哪些场景下使用,其实也就是在问他们的区别.computed也就是计算属性,它可以帮助我们将在模板中的一些稍微复杂的逻辑计算放回到js代码中 ...

  3. DOM选择器之元素其他节点选择器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 【算法总结】强化学习部分基础算法总结(Q-learning DQN PG AC DDPG TD3)

    总结回顾一下近期学习的RL算法,并给部分实现算法整理了流程图.贴了代码. 1. value-based 基于价值的算法 基于价值算法是通过对agent所属的environment的状态或者状态动作对进 ...

  5. python入门教程之九日期时间常用操作

    Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示. Py ...

  6. [Java/LeetCode]算法练习:二进制间距(868/simple)

    1 题目描述 题目来源: https://leetcode-cn.com/problems/binary-gap/ 给定一个正整数 n,找到并返回 n 的二进制表示中两个 相邻 1 之间的 最长距离 ...

  7. 帝国cms 随机调取新闻

    <?php $hits_r = $empire->query("select * from {$dbtbpre}ecms_music as t1 join (select rou ...

  8. Kubernetes入门实践(搭建Wordpress网站)

    容器只是对单个进程的隔离和封装,实际的应用场景要求许多的应用进程互相协同工作,因此出现了容器编排,Kubernetes将集群中的计算资源定义为节点(Node),其中又划分成控制面和数据面两类,控制面是 ...

  9. Vue的生命周期的详解

    Vue的生命周期   Vue的生命周期是每个使用Vue框架的前端人员都需要掌握的知识,以此作为记录.   Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue() 开始就是vue生 ...

  10. Python获取jsonp数据

    使用python爬取数据时,有时候会遇到jsonp的数据格式,由于不是json的,所以不能直接使用json.loads()方法来解析,需要先将其转换为json格式,再进行解析.在前面讲了jsonp的原 ...