03 - 通用编程概念

通用编程概念:变量、基本类型、函数、注释和控制流等。

一、变量与可变性

在之前也提到过,Rust 中的变量默认是不可变的,单从变量这个名称来讲,变量按理说量是可变的,但在 Rust 中却不可变,原因是 Rust 的核心是要保证安全,不过也提供让你可以使用的可变变量方法。在变量声明时使用 mut 关键字

二、变量与常量之间的不同

常量,记住一点就是常量总是需要标注类型。下面为声明一个常量的例子:

const MAX_POINTS: u32 = 100_000;

在 Rust 程序中,约定俗成地使用以下划线分隔的全大写字母来命名一个常量,并在数值中插入下划线来提高可读性。

三、隐藏

让我们来看一个隐藏例子

fn main() {
    let x = 5;
    let x = x + 1;
    let x = x * 2;

    println!("The value of x is: {}", x);
}

通过重复 let x = 语句将前一个值进行了隐藏,隐藏机制不同于将一个变量声明为 mut,因为如果不是在使用 let 关键字的情况下重新为这个变量赋值,则会导致编译错误。隐藏机制与 mut 的另一个区别在于,由于重复使用 let 关键字会创建出新变量,所以可以在复用变量名称的同时改变它的类型。

let spaces = " ";
let spaces = spaces.len();

以下却会报错

let mut spaces = " ";
spaces = spaces.len();

四、数据类型

数据类型的子集:标量类型和复合类型。

4.1 标量类型

Rust 中内建了 4 种基础的标题类型:整数、浮点数、布尔值及字符。

长度 有符号 无符号
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
arch isize usize

以上类型只说明最后一栏,isize 和 usize 两个特殊类型,它们的长度取决于程序运行的目标平台,在 64 位架构上,它们就是 64 位的,在 32 位架构上,它们就是 32 位的,两者主要用作于某些集合的索引。

在 Rust 中如果以 debug 模式编译,那么就会在程序中包含整数溢出的运行时检测代码,并在整数溢出发生时触发程序的 panic,Rust 用 panic 描述程序因为错误而退的情形;如果使用的 release 模式编译,那么就不会包含那些可能会触发 panic 的检查代码,作为替代,Rust 会在溢出发生时执行二进制补码环绕,简而言之,任何超出类型最大值的数值都会被 "环绕" 为类型的最小值。以 u8 为例,256 会变为 0,251 会变成为 1,以此类推。如果想显式地进行环绕行为,那么可以使用标准库中的 Wrapping 类型。
浮点类型 f32 和 f64,在 Rust 中,默认会将浮点数字字面量的类型推导为 f64。

let x = 2.0;		// f64
let y: f32 = 3.0;	// f32

布尔类型为 true 和 false 两类值

let t = true;
let f: bool = false;	// 附带了显式类型标注的语句

字符类型 char 用单引号来表示,字符串用双引号

let c = 'r';
let z = 'R';

char 类型占 4 个字节,是一个 Unicode 标量值。

4.2 复合类型

Rust 提供了两种内置的基础复合类型:元组和数组。

// 声明一个元组的例子
let tup: (i32, f64, u8) = (500, 6.4, 1);

元组有一个固定的长度,无法在声明结束后增加或减少其中的元素数量。

fn main() {
    let tup = (500, 6.4, 1);
    let (x, y, z) = tup;

    println!("The value of y is: {}", y);
}

将 tup 拆分为 3 个不同的部分:x、y 和 z,这个操作被称为解构,除了解构,还可以通过索引并使用点号来访问元组中的值。

fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);
    let five_hundred = x.0;
    let six_point_four = x.1;
    let one = x.2;

    println!("The value of fivee_handred is: {}", five_hundred);
    println!("The value of six_point_four is: {}", six_point_four);
    println!("The value of one is: {}", one);
}

数组与元组不同,数组中的每一个元素都必须是相同的类型,Rust 中的数组长度也是固定的,一旦声明后就也不能随意更改其大小,这与其他某些语言有所不同。

let a = [1, 2, 3, 4, 5];

当你想在栈上而不是堆上为数据分配空间时,或者想要确保总有固定数量的元素时,数组是一个非常有用的工具,Rust 标准库也提供了一个更加灵活的动态数组 (vector) 类型,动态数组可由用户自由调节数组长度,如果不确定什么时候使用普通数组还是动态数组,那就先使用动态数组就好了。

为了写出数组的类型,需要使用一对方括号,并在方括号中填写数组内所有元素的类型,一个分号及数组内元素的数量

let a: [i32; 5] = [1, 2, 3, 4, 5];

如果想创建一个含有相同元素的数组,可以在方括号中指定元素的值,并接着填入一个分号及数组的长度

let a = [3; 5];	// => let a = [3, 3, 3, 3, 3]

访问数组方式同 C 语言一样,非法访问索引外的数组中的值会出错。

五、函数

函数用 fn 关键字来声明,Rust 代码使用蛇形命名法 (只使用小写字母进行命名) 来作为规范函数和变量名称的风格。

fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("Another function.");
}

函数可放在 main 函数前也可放在其后面,不像 C 语言,放在 main 函数后面还需要对函数进行声明。

5.1 函数参数

fn main() {
    println!("Hello, world!");
    another_function(5);
}

fn another_function(x: i32) {
    println!("The value of x is: {}", x);
}

必须显式地声明每个参数的类型,这是在 Rust 设计中设计者们经过慎重考虑做出的决定,函数参数列表使用逗号分隔多个参数

fn main() {
    println!("Hello, world!");
    another_function(5, 6);
}

fn another_function(x: i32, y: i32) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

5.2 函数体中的语句和表达式

语句没有返回值,一个表达式有返回值,比如 x = y = 5 可能在别的语言成立,但在 Rust 中并不成立。

fn main() {
    let x = 5;

    // 以下为一个代码块,计算出 4 作为结果,赋给 y
    // x + 1 后并没有分号
    let y = {
        let x = 3;
        x + 1
    };

    println!("The value of y is: {}", y);
}

5.3 函数返回值

可不用为返回值命名,但需要在箭头符号 (->) 的后面声明它的类型

fn five() -> i32 {
    5
}

fn main() {
    let x = five();

    println!("The value of x is: {}", x);
}

再来一个例子

fn main() {
    let x = plus_one(5);

    println!("The value of x is: {}", x);
}

fn plus_one(x: i32) -> i32 {
    x + 1
}

六、注释

Rust 中用 // 来表示注释。

七、控制流

Rust 中用来控制程序执行流的结构主要是 if 表达式与循环表达式。

7.1 if 表达式

if 后的表达式必须为一个 bool 类型的值

fn main() {
    let number = 3;

    if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }
}

Rust 不会自觉尝试将非布尔类型的值转换为布尔类型,必须显式地在 if 表达式中提供一个布尔类型作为条件。

7.2 使用循环重复执行代码

Rust 提供了 loop、while、和 for 循环工具。loop 关键字来指示 Rust 反复执行某一块代码,直到显式地声明退出为止。

fn main() {
    loop {
        println!("again!");
    }
}

以上代码会无限输出 again!,直到按 Ctrl + C 强制退出。另外可使用 break 关键字来通知程序退出

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };
    println!("The result is {}", result);
}

while 循环例 1

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{}!", number);
        number = number - 1;
    }

    println!("LIFTOFF!!!");
}

while 循环例 2

fn main() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {
        println!("the value is: {}", a[index]);
        index = index + 1;
    }
}

以上代码和下面这段代码等效,效率更高

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a.iter() {
        println!("The value is: {}", element);
    }
}
fn main() {
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("LIFTOFF!!!");
}

八、练习

婓波那契数列

use std::io;

fn main() {
    println!("请输入婓波那契数列阶数(n > 2):");
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed to read line");
    let number: i32 = match input.trim().parse() {
        Ok(num) => num,
        Err(_) => {
            println!("请输入整数,请勿输入无关符号!");
            return;
        }
    };
    println!("婓波那契数列:");
    let mut i = 1;
    while i <= number {
        print!("{} ", fibonacci(i));
        i = i + 1;
    }
}

fn fibonacci(x: i32) -> i32 {
    if x < 3 {
        1
    } else {
        fibonacci(x - 2) + fibonacci(x - 1)
    }
}

image

posted @ 2023-09-05 11:01  煙沫凡塵  阅读(28)  评论(0编辑  收藏  举报