最新网站备案教程,搜索引擎推广的基本方法,wordpress搬家后网页空白,小型企业互联网解决方案变量与作用域
变量的声明与初始化
Rust的基本语法格式如下#xff1a;
fn main(){let bunnies 2;
}语句以分号结尾#xff0c;用花括号包含语句块。 Rust的语法其实借鉴了很多其他的语言#xff0c;比如C语言和Python#xff0c; 所以变量定义的格式看起来也跟很多我们…变量与作用域
变量的声明与初始化
Rust的基本语法格式如下
fn main(){let bunnies 2;
}语句以分号结尾用花括号包含语句块。 Rust的语法其实借鉴了很多其他的语言比如C语言和Python 所以变量定义的格式看起来也跟很多我们熟悉的其他语言相似。Rust中使用let关键字声明一个变量。在上面的例子中 我们声明了一个变量bunnies, 并且初始化了它的值为2.
Rust是一种强类型的语言那么在上面的语句中哪里标注了这个变量的类型呢在Rust编程中如果Rust能准确的识别这个变量的类型那么我们不需要显式的标注变量的类型也不需要像C#那样标注一个auto表示它的类型是自动识别的。
如果需要显式的标注一个变量的类型可以像下面的例子一样做, 在变量名后加个: 后面再写上变量的类型如下i32代表有符号的32位整型。
fn main(){let bunnies: i32 2;
}与python类似rust也可以在一行语句中定义多个变量。如下例子便可以在一行代码中为两个变量初始化
fn main(){let (bunnies, carrots) (8, 50);
}变量不可变
在Rust中变量默认其实是不可变的也就是说一旦对一个变量赋值以后其值默认是不可被修改的。这一特点与大多数的其他编程语言都不同其他编程语言的变量默认是随时可以被重新赋值的。那为什么Rust要将变量设置为默认不可变的呢这就要提到上一章中我们提到的Rust的三个特性了
内存安全 如果变量在运行过程中始终不变这可以避免很多bug的发生变量不可变这一设计极大的提高了Rust的内存安全特性。无畏并发 不变的变量可以被多个线程在不加锁的情况下共享这也使得Rust的并发更安全可靠。高性能 不变的变量使得编译器可以对其进行额外的优化从而提高了代码的执行速度提高了程序运行性能。
但是不得不承认我们在编程中一定会遇到需要修改变量的需求 如果我们直接修改变量的值编译便会报错例如下面的代码
fn main(){let bunnies: i32 2;bunnies 3; // Error!
}如果运行上面的代码将会得到下面的报错可以看到报错中非常明确的指出了代码的问题所在并且还指出了修改建议 在报错的最上面给出了错误的描述也就是不能对不可变变量进行二次赋值。在报错中也指出了错误所在的位置第3行第5列。接下来还对整个错误的上下文进行了说明告诉我们在第2行的时候对变量bunnies已经赋值然后再第3行再次对不可变变量bunnies进行了赋值因此报错。接着还提出了修改建议让我们在第2行的变量名前面加上mut, 使其成为一个可变变量也许能修复这个问题。在最后一行如果上面的提示还不能解决问题还可以运行rustc --explain e0384来查看错误的完整描述。 按照错误提示我们将代码修改后如下便可以成功运行了
fn main(){let mut bunnies: i32 2;bunnies 3; // Error!
}常量
在Rust中常量constant其实也属于变量的一种 相比普通的不可变变量它更加的不可变。定义一个常量包含以下四个关键步骤
以const而不是let声明变量名格式为全大写字母加下划线分隔必须声明变量类型常量的值必须时编译时可确定值的表达式
下面是普通变量和常量声明的对比
let wrap_factor ask_scotty(); // 变量
const WRAP_FACTOR: f64 9.9; // 常量定义一个常量比变量麻烦很多那为什么还要用常量呢
常量可以在函数作用域外或者模块外进行定义而在任意的地方使用常量会在编译时被静态的写入可执行文件使得运行速度很快Rust官方在每个发布版本中都对const类型增加了越来越多的功能和优化在可以使用const的地方使用const是一个好的选择
作用域
每个变量都有各自的作用域只有在变量的作用域中变量才能被使用。代码的作用域通常是从变量被创建的地方开始到变量所在的代码块结束 在这个范围中的子代码块中变量仍然是可以被访问的。
注 代码块是一组被花括号包含的语句
fn main() {let x 5;{let y 99;println!(x {}, y {}, x, y);}println!(x {}, y {}, x, y); // Error!
}在上面的代码中 变量x在main函数的代码块中被定义其中定义了一个子代码块在子代码块中定义了一个变量y, 在子代码块中x 和 y都可以被访问 在子代码块结束时 y立刻被销毁Rust中没有任何的垃圾回收器变量总是在离开作用域后被立即销毁因此第二个println!语句不能访问变量y而发生错误。
然而我们不用担心这会在运行时发生bug 因为这种错误会在编译时就被暴露出来。
变量隐藏
Rust中也存在变量隐藏的现象
fn main() {let x 5;{let x 99;println!(x {}, x);}println!(x {}, x); // Error!
}运行结果应该如下
x 99
x 5在上述代码中我们在子代码块外部定义了一个变量x并赋值为5, 在子代码块中x的值被覆盖为内层代码块中的值99。当离开了内层代码块后内层的变量x被销毁 x的值又变回了外层代码块中的5.
再来看一个例子
fn main() {let mut x 5; // x is mutablelet x x; // x is now immutable
}这个例子中第一个x被隐藏了这其实相当于重新声明并初始化了x这个变量在编译过程中 Rust甚至能识别到这种情形并优化执行的过程并不会真的先定义一个可变的x, 再用一个新的x去覆盖它而是直接定义一个不可变的变量x并为其赋值为5.
再看一个例子
fn main() {let meme More cowbell!;let meme make_image(meme);
}在上述代码中 变量meme甚至能被改变类型从字符串变成了图片。
变量与内存安全
在Rust中在使用一个变量前必须确保这个变量被初始化。
情景A
fn main() {let enigma: i32;println!({}, enigma); // Error!
}可以看到报错提示我们变量虽然被声明了但是没有被初始化。
情景B
fn main() {let enigma: i32;if true{enigma 42;}println!({}, enigma); // Error!
}即时是在一个恒为真的判断语句中为变量进行了初始化编译器仍会报错 因为判断语句只有在运行时才能被判别最终的结果因此在编译时没办法确保该变量一定会被初始化。
为了保证变量一定被初始化可以将上述代码改为如下
fn main() {let enigma: i32;if true{enigma 42;} else {enigma 7;}println!({}, enigma); // Error!
}如果在C语言中使用了一个未初始化的变量会出现什么现象呢如下代码
include stdio.h
int main(){int enigma;printf(%d\n, enigma);
}这将不会导致编译报错程序可以正常运行但是会输出一个不可预测的结果因为声明变量后 C语言就会在内存分配一个地址而这个内存地址中存储的是什么数据我们不得而知它可能是任何东西。
小结
本章介绍了Rust中变量的种类声明与赋值方式以及变量的作用域和隐藏特性。下一章将介绍Rust的函数及模块系统。