Rust 基础践行 | 🏆 技术专题第十期征文

763 阅读7分钟

安装

www.rust-lang.org/zh-CN/tools…

在线运行

play.rust-lang.org/

创建项目

 cargo new hello_world  // 创建项目
 cargo run  // 运行

更多细节,自行查找资料。

变量

1. 整形

整形变量包含多种范围的变量类型,如下:

类型有符号无符号
8位i8u8
16位i16u16
32位i32u32
64位i64u64
128位i128u128
archisizeusize

举例

fn main() {
    let num: i8 = -1; // 有符号 整形
    println!("i8 -> {}", num);

    let num: String = "hello".to_string(); // 无符号 整形
    println!("i8 -> {}", num);
}

存储范围公式

  • 有符号 2n12n11-2^{n - 1} \quad ~ \quad 2^{n - 1} - 1

以 8位有符合存储类型 i8,进行存储类型计算,设 n = 8, 代入上方“公式”, 得出结果范围: -127 ~ 127

  • 无符号 02n10 \quad ~ \quad 2^{n} - 1

以 8位无符号存储类型 u8,进行存储类型计算,设 n = 8, 代入上方“公式”, 得出结果范围: 0 ~ 255

进制转换

Rust 中的 进制符号

0b:(B)二进制 - 0o:(O)八进制 - 0d:(D)十进制 - 0x:(H)十六进制

fn main() {

    let num_hex: u8 = 0xff; // 16进制 -> 10 进制 自动类型转换
    println!("0x to 0d -> {}", num_hex);

    let num_octal: u8 = 0o77; // 8进制 -> 10 进制 自动类型转换
    println!("0o to 0d -> {}", num_octal);

    let num_binary: u8 = 0b111; // 2进制 -> 10进制 自动类型转换
    println!("0b to 0d -> {}", num_binary);

    let num_byte: u8 = b'A'; // Ascii 码 -> 10进制 自动类型转换
    println!("Ascii码 to 0d -> {}", num_byte);
}

进制转换公式

2. 小数类型 - float 浮点

浮点类型 包含: f32f64 两种类型;

fn main(){

    let num: f32 = 1.2;
    println!("f32 小数 -> {}", num);
    
    let num: f64 = 12.2;
    println!("f64 小数 -> {}", num);
    
    let num = 12.2; // 如果不指定,默认是 f64 类型
    println!("f64 小数 -> {}", num);
    
}

3. 逻辑类型 - bool 布尔

布尔类型 包含:truefalse 两种结果,占用1个字节;

fn main() {
    let t = true; // 自动推导为 bool 类型

    let f: bool = false; // 指定为逻辑类型
}

4. 字节类型 - char

在 rust 中,字节类型 用 '' 单引号 包裹,并且占用4个字节,使用unicode表示,这样的好处是,可以表示的内容范围更多,

fn main() {

    let z = 'z';
    println!("char -> {}", z);
    
    let z = 'ℤ';
    println!("char -> {}", z);
    
    let z = '😻';
    println!("char -> {}", z);
    
}

复合类型

1. 元组类型
  • 元组的长度是固定的:声明后,它们的大小就无法进行改变;
  • 元组的下标以0开始计算,依次叠加1个步长 (和数组的计算方式一样);
  • 元组可以包含多个不同的类型,以 “,” 分割;
fn main(){
    
    let tup: (i32, f64, u8) = (500, 6.4, 1);

    let (_, y, _) = tup; // 在解构元组类型时,可以 使用 _ 进行占位,

    println!("元组 -> {}", y);

    println!("元组 -> {}", tup.1); // 通过 元组.[下标] 进行 读取 元组 类型的 对应下标值
    
}   
2. 数组类型
  • 在Rust 中, 数组类型的长度是固定的,在声明之后,不可以进行改变;
fn main(){

    let a: [i32; 5] = [1, 2, 3, 4, 5]; // 5个相同类型的 数组;
    println!("数组 -> {}", a[0]);

    let a = [1; 3]; // 3个相同数组元素的数组类型;
    println!("数组 -> {}", a[0]);
    
}
 
额外收获

在定义数组类型时,可以使用 [i32;5] 的方式,定义一个支持5个相同类型长度的元素;此方式仅适用于数组类型;

在为数组类型赋值时,可以使用 [1;3] 的方式,创建3个都是元素1的数组类型;此方式仅适用于数组类型;

元组类型 与 数组类型的 区别

相同点

  • 在声明类型后,类型的长度都不可以改变;
  • 下标都是 从 0 开始;

不同点

  • 元组类型 采用 () 括号包裹, 逗号 分割;
  • 数组类型 采用 [] 方括号包裹,同时也是采用 逗号分割;
  • 元组类型可以解构;
  • 数组类型不支持解构;
  • 元组类型 通过 (. 点)[下标]的形式访问值;
  • 数组类型 通过 [下标]的形式访问值;

函数

语法规则


fn main() {
    println!("这里是函数的天下");
    fn_1();
    fn_2(3);
    fn_3(3, 100);
    let num: i8 = fn_4();
    println!("函数返回值 ->{}", num);

    println!("有参数的函数返回值 ->{}", fn_5(1));
}

fn fn_1() {
    println!("无参数的函数")
}

fn fn_2(x: i8) {
    println!("只有一个参数的函数 -> {}", x);
}

fn fn_3(x: i8, y: i32) {
    println!("N个参数的函数 -> ({} , {})", x, y);
}

fn fn_4() -> i8 {
    5
}

fn fn_5(x: i8) -> i8 {
    x + 5
}

表达式

在 Rust 中,表达式的 最后一行代码没有“;” 分号结尾,说明该行语句是带有返回句柄的赋值语句;如果加了分号就表示是一条语句,没有返回句柄。

fn main(){

    let y = {
        let x = 3;
        x + 1
    };

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

控制语句

1. if语句

fn main() {
    let flag: bool = true;
    
    // 单判断分支
    if flag {
        println!("True");
    } else {
        println!("False");
    }

    let age: i32 = 18;

    // 多判断分支
    if age > 18 {
        println!("大于18");
    } else if age < 18 {
        println!("小于18");
    } else {
        println!("等于18");
    }

    let condition = true;

    // 类似 三目运算符, 分支出口的表达式类型必须一致
    let number = if condition { 5 } else { 6 };
    
    println!("The value of number is: {}", number);
}

2. loop 循环语句

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {}", result);
}

3. while 循环语句

fn main() {
    let mut number = 3;

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

        number -= 1;
    }

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

4. for 循环语句

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

    for element in a.iter() {
        println!("the value is: {}", element);
    }
}

mut 可变不可变类型

为什么Rust 中,存在不可变的类型?

在 javascript 弱类型语言中,不可变类型只有 const 定义的变量才具有不可变的作用,但是对于 class 的引用也只是 引用地址、基本类型的不可变,class 的属性 方法还是可以动态绑定,修改的。

在 Rust 中,定义一个不可变的变量,是不允许为此变量再次进行赋值的,如果想要赋值,只能是如下方式


let name = 'hello';

name = 'word'; // 错误, 不允许再次赋值, 因为是不可变量

let name = 'word'; // 正确, Shadowing - rust 特性,可以重复定义一个变量 去重新赋值

let name = 12; // 错误, 虽然rust 提供了重新定义变量赋值的思想,但是 起码需要给定一个 一致的类型,因为该 name 变量 在第一次定义时,已被确定为字符串类型,由于 (字符串 != 数字) 所以失败。

let name: u8 = 12; // 正确, 因为重新指定了变量的类型,虽然变量名还一样,但是类型已经发生改变,使得 “=” 两边的类型一致。  

Rust 的可变类型?

可变类型就比较好理解了,指的是定义出来的变量可以被多次赋值,条件(类型一致)

let mut name = 'hello';

name = 'word'; // 正确, 因为该变量首次定义时,已被声明为可变类型的变量

name = 12; // 错误, 类型不一致, 搞毛啊

可变与不可变类型的区别?

在上面大致介绍了,Rust 中的可变与不可变类型,那么他们的区别其实也就是那么几点。


let mut name = 'hello'; // 可变类型

let age = 12; // 不可变类型

区别:可变类型需要使用 mut 修饰变量;相反 不可变类型不需要。

不可变类型 是否可以 重新赋值?

不可以重新赋值,但是我们可以采取 Rust 的 Shadowing 技术,我理解为是衍生变量。 可以在使用的地方再次定义相同变量名的变量进行赋值。

let name = 'hello';

/* ... 此处省略了无数行代码 ... */

let name = 'word';

常见问题

1. 出现 Blocking waiting for file lock on package cache

修复:rm -rf ~/.cargo/.package-cache

2. 替换镜像源

打开 /.cargo/config 文件

替换如下内容

[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

🏆 技术专题第十期 | 一起谈谈语言新宠 Rust