亲宝软件园·资讯

展开

Rust 入门 (三)_上

shanpengfei 人气:1

这部分我们学习 rust 语言的 变量、数据类型、函数、注释、流程控制 这五个方面的内容。本文我们介绍前两个内容,下一篇文章介绍后三个内容。

变量

默认情况下,rust 语言中声明的变量是不可变的,比如如下代码:

fn main() {
    let x = 5;
    println!("x 的值是: {}", x);
    x = 6;
    println!("x 的值是: {}", x);
}

我们先来跑一下这段代码:

cargo run                                                                                                                                                                                         
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: make this binding mutable: `mut x`
3 |     println!("x 的值是: {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0384`.

通过运行结果,我们发现这段代码有问题的,然后我们从报错信息中抓取关键信息:cannot assign twice to immutable variable,它的意思是 不可变变量不能进行二次赋值。但是有些时候,我们也需要修改变量的值,应该怎么办呢,在变量名的前面,let 关键字的后面添加一个关键字 mut 就行了,我们来试试:

fn main() {
    let mut x = 5;
    println!("x 的值是: {}", x);
    x = 6;
    println!("x 的值是: {}", x);
}

运行一下代码:

cargo run                                                                                                                                                                                      
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 3.53s
     Running `targethttps://img.qb5200.com/download-x/debug/hello_cargo`
x 的值是: 5
x 的值是: 6

这种不可变变量的设计有着很多安全方面的考虑,这里不再赘述。谈到这里,很容易联想到编程语言的另一个概念——常量,那二者有什么区别呢?
1.常量不能使用 mut 关键字修饰,常量在任何情况下都是不可变的(变量是在默认情况下不可变)。
2.常量使用 const 关键字来声明,而变量使用 let 关键字来声明。
3.常量需要在常量名后面紧跟冒号和类型,例如 const MAX_POINTS: u32 = 100_000;,而变量可以省略冒号和类型的修饰。
4.常量的作用域是任何作用域,包括全局作用域。
5.常量只能使用常量表达式赋值,而不能使用函数结果或者其它运行时产生的值。

注:这是说明一下,常量通常使用大写字母和下划线 _ 来命名。



我们再来说一个变量的特性——覆盖。在上一篇写猜数字游戏的文章中,我们做数字类型转换的时候,新类型的名字使用了旧类型的名字,这种情况就是覆盖。先来个实例:

fn main() {
    let x = 5;
    println!("x 的值是: {}", x);
    let x = 6;
    println!("x 的值是: {}", x);
}

我们来看运行结果:

cargo run                                                                                                                                                                                          
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s
     Running `targethttps://img.qb5200.com/download-x/debug/hello_cargo`
x 的值是: 5
x 的值是: 6

通过结果可以发现,第二个使用 let 关键字修饰的不可变变量 x 把第一个 x 覆盖了,也就是说把 x 的值从 5 改成了 6。那这和 mut 有什么区别呢?
1.覆盖的第二个变量需要使用 let 关键字修饰,如果没有 let 关键字,则会报错。
2.覆盖的第二个变量不仅可以改变值,还可以修改变量的类型;而 mut 不可以改变类型。

这里举两个例子来说明第二个区别:

fn main() {
    let space = "abc";
    println!("space 代表的是:{}", space);
    let space = space.len();
    println!("space 代表的是:{}", space);
}

先来运行第一个例子:

 cargo run                                                                                                                                                                                          
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.22s
     Running `targethttps://img.qb5200.com/download-x/debug/hello_cargo`
space 代表的是:abc
space 代表的是:3

然后看第二个例子:

fn main() {
    let mut space = "abc";
    println!("space 代表的是:{}", space);
    space = space.len();
    println!("space 代表的是:{}", space);
}

跑一下第二个例子:

cargo run                                                                                                                                                                                         
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     space = space.len();
  |             ^^^^^^^^^^^ expected &str, found usize
  |
  = note: expected type `&str`
             found type `usize`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `hello_cargo`.

To learn more, run the command again with --verbose.

可以轻易看到二者的区别,好了,接下来我们看 rust 的基本类型。

数据类型

rust 的数据类型就是在编译期间告诉 rust 的编译器如何处理这些数据。在这里,我们会了解到两种数据类型:基本数据类型和组合数据类型。

基本数据类型

基本数据类型也就是简单值,rust 主要包含了 4 种基本数据类型,分别是整型、浮点型、布尔型和字符型。你可能在其他语言中见过这些类型,现在,我们来看一下它们在 rust 语言中是怎么样的。

整型

整型是不包含小数的数字类型。整型包含了两种类型:i 打头的有符号整型和 u 打头的无符号整型。我们使用一个表格来描述 rust 的整型:


|占用空间 |有符号整型 |无符号整型|
|:--:|:--:|:--:|
|8-bit |i8 |u8
|16-bit |i16 |u16
|32-bit |i32 |u32
|64-bit |i64 |u64
|128-bit |i128 |u128
|格式 |i+长度 |u+长度

整型在使用过程中默认类型是 i32。

浮点型

浮点型包含了两种类型:单精度浮点型 f32,双精度浮点型 f64。浮点型在使用过程中默认类型是 f64。

数据操作

rust 支持的基本数据操作有:加 +,减 -,乘 *,除 /,取模 %。

布尔型

布尔型通常有两个值:true和false。它占用 1 个字节,使用 bool 关键字来声明。

字符型

rust 的字符类型占用 4 个字节,它的值是使用单引号 ' 引起来的。

组合数据类型

组合数据类型是把多个值组合成一个类型。在 rust 中,组合数据类型有两种:元组和数组。

元组

元组是把多个基本类型组合成一个组合类型。它有一个确定的长度,一旦确定就不能再次加减元素了。我们先来看一个元组的实例:

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    println!("第0个值:{}, 第1个值:{}, 第2个值:{}", tup.0, tup.1, tup.2);

    let (x, y, z) = tup;
    println!("x的值:{}, y的值:{}, z的值:{}", x, y, z);
}

它运行的结果是:

cargo run                                                                                                                                                                                          
   Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.23s
     Running `targethttps://img.qb5200.com/download-x/debug/hello_cargo`
第0个值:500, 第1个值:6.4, 第2个值:1
x的值:500, y的值:6.4, z的值:1

元组的取值有两种方式,一种是把元组解构成多个变量,另一种就是使用 . 的方式,顺序是从 0 开始。

数组

数组和元组不一样的地方是:数组只能使用相同的数据类型。数组和元组相同的地方是:长度一旦确定就不能加减元素了。如果想改变数组的长度,可以使用 vector 类型,后续文章会介绍 vector 类型的情况。而且数组还有一个特性,它会把数据分配到栈内存,而不是堆内存。下面举几个常用的数组的例子:

fn main() {
    // 定义一个简单的数组
    let a = [1, 2, 3, 4, 5];

    // 定义一年 12 个月,而且不需要增减月份,那么可以直接定义包含 12 个月份的数组
    let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

    // 定义包含 5 个元素的 i32 类型的数组
    let a: [i32; 5] = [1, 2, 3, 4, 5];

    // 数组的值是 5 个 3
    let a = [3; 5];

    // 取值
    println!("a[3]的值是:{}", a[3]);
    println!("a[9]的值是:{}", a[9]);  // 编译时这里会报错:error: index out of bounds: the len is 5 but the index is 9
}

数组的取值方式是以中括号 [0] 的方式,顺序是从 0 开始。如果取值越界,rust 会在编译期告诉你,这就是 rust 安全原则的第一个例子。


这一节未完,待续~~~

欢迎阅读单鹏飞的学习笔记

加载全部内容

相关教程
猜你喜欢
用户评论