前端er快速入门rust基础(1)

2 阅读6分钟

前端er快速入门rust基础

前端现在环境太好啦~

外包都不要民办大学的人了。

image-mfte.png 😑,苦前端久已。

不如直接入手rust。这里通过我一个前端小菜鸟的角度快速入门rust

材料准备

看文档自行安装

安装完成后可以用cargo --version做测试

变量

这里简单说下,rust中的命名标志符跟ts有点像。但是功能有点差距。

let

借用官网的例子

fn main() {
    let x = 5;
    println!("The value of x is: {x}");
    x = 6; // ❌
    println!("The value of x is: {x}");
}

单纯使用let定义的变量是不可变的,需要使用mut 关键字定义

fn main() {
    let mut x = 5;
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

以上是同类型的变更。

但是!如果你需要变更数据类型,比如字符串转数字,需要使用let 重新定义

这里就跟js中不同了哦,js是个弱类型,你可以随便改~跟ts也不同,ts需要写联合类型或者断言。

let mut guess: String = String::new(); // 原类型string


let guess: u32 = guess.trim().parse().expect("Please type a number"); 
// 经过parse过后,转换成u32类型
// 此处的u32就是类型啦,跟ts中的number差不多。具体可看下文

此处的excpet 代表转换出错,会输出Please type a number

关于let的shadowing

这里简单说下,在rust中,你可以对同名的变量一直使用let修改。但是这里涉及到一个作用域的概念。

作用域
function main() {
    let x: number = 5;

    x = x + 1;

    {
        let x: number = x * 2; // ❌  ReferenceError: Cannot access 'x' before initialization
        console.log(`The value of x in the inner scope is: ${x}`);
    }

    console.log(`The value of x is: ${x}`);
}

main();

在ts或者js中在花括号作用域中重新声名let x ,会导致一个问题,也就是代码中提到的Cannot access 'x' before initialization,无法在变量初始化之前访问,这是js的知识,变量提升~但是在rust中,这样的写法是合理合规的:

fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    println!("The value of x is: {x}");
}
$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/variables`
The value of x in the inner scope is: 12
The value of x is: 6

这里可以看到,输出了12 和6; 说明以下情况:作用域中的let不会修改外部的值!

这就是rust所谓的Shadowing,内部作用域中重新let变量,不会导致外部变量发生改变~

const

const就是完全不能改变的常量!

const 不允许使用mut !并且,必须使用类型修饰!并且,const只能是固定值,不能是其他变量合并的值!

变量类型

!记住官网的话,rust是静态类型语言!

这就意味着在代码编译前,就应该确定所有变量、常量的类型。

这里简单说下跟ts的差别

Number

ts中只要是数字,都可以使用Number进行类型修饰,或者对于超大类型的bigint。

在rust中要分成以下几种

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

这种写法熟悉其他语言的应该比较清楚,其实就是个数字大小限制

比如 n-bit,就是 -(2n - 1) 到 2n - 1 - 1 在内的数字。

最后的arch就是依赖于计算机架构的,计算机架构为32位,他就是32,以此类推。

关于溢出

既然限制了变量大小,那么一定也有溢出的问题存在。

比如:

let x:u8 = 244;
x = x + 8888; // ❌

在编译的时候会直接报错,但是在release的时候并不会检查这个。

此时,可以使用显式处理溢出:

  • check_*
let x:u8 = 244;
match x.check_add(8888) {
	Some(value) => println!("Sum: {}", value),
    None => println!("Overflow occurred!"),
}
  • wrapping_*
let x:u8 = 244;
let sum = x.wrapping_add(8888);
println!("Sum: {}", sum);
  • overflowing_*
let x:u8 = 244;
let (sum, overflow) = x.overflowing_add(8888);
if overflow {
    println!("Overflow occurred!");
} else {
    println!("Sum: {}", sum);
}
  • saturating_*
let x:u8 = 244;
let sum = x.saturating_add(8888);
println!("Sum: {}", sum);

一共有四种:

所有模式下都可以使用 wrapping_* 方法进行 wrapping,如 wrapping_add

如果 checked_* 方法出现溢出,则返回 None值

用 overflowing_* 方法返回值和一个布尔值,表示是否出现溢出

用 saturating_* 方法在值的最小值或最大值处进行饱和处理

float

这里需要关注,rust与java等语言相同,浮点类型的需要使用f32或者f64 ,所有的浮点型数据都是有符号的!

复合类型

复合类型有两个原生的,元组和数组

元组没啥好讲的,跟ts一样,固定长度,固定类型!

简单例子:

let tup:(i8,f32,u8) = (12,1.33,2)
// 访问方式
let (x,y,z) = tup; // 此处类似解构赋值

let a = tup.0;

// 0 代表位置,类似于数组的角标

数组

Rust中的数组也是定长的!需要谨记!如需要动态增减长度,需要使用另外的方式来做定义。

定义定长数组有三种方式:

let arr1 = [1, 2, 3, 4, 5]; // 第一种方式,自动推断类型
    let arr2: [i32; 5] = [1, 2, 3, 4, 5]; // 第二种方式,显示声明类型
    let arr3 = [3; 5]; // 第三种方式,初始化为相同的值,也就是 3是每个元素的值,5为长度。

取值方式跟js没有区别,也是用数组下标进行获取。

let len: usize = arr1.len();
    // .. 为左闭右开区间 [0, len) 0 <= i < len  ..= 为左闭右闭区间 [0, len] 0 <= i <= len
    for i in 0..len {
        println!("{}", arr1[i]);
    }

这里需要记住 ..* 操作符,后面有讲。

Vec 向量

这个东西就比较像数组了,但是定义方式不一样:

let mut vec: Vec<u8> = Vec::new(); // 定义空向量
let mut vec2 = vec![1, 2, 3, 4, 5]; // 定义有默认值的向量

当然,我们在js中定义的数组元素可以是任意类型的,ts中可以用any大法或者联合类型,或者接口来实现。在rust中需要使用枚举类型来操作~当然枚举类型可用与多处,这里简单写一下向量的定义

enum MutPtr {
        Number(u32),
        Text(String),
    }
    let mut vec3: Vec<MutPtr> = Vec::new();
    vec3.push(MutPtr::Number(8));
    vec3.push(MutPtr::Text(String::from("123123131")));
    for element in vec3.iter() {
        match element {
            MutPtr::Number(value) => println!("Number: {}", value),
            MutPtr::Text(value) => println!("Text: {}", value),
        }
    }

越界问题

无论是哪一种语言都会出现数组越界的问题,js中数组越界不会导致程序崩溃,rust会!所以我们得用一种合适的方式去处理:

  1. 使用get去获取数组或者向量的option

    let arr = [1, 2, 3];
    if let Some(element) = arr.get(2) {
        println!("The third element is {}", element);
    } else {
        println!("Index out of bounds.");
    }
    
  2. 通过length去处理

    let arr = [1, 2, 3];
    let index = 2;
    if index < arr.len() {
        println!("The element is {}", arr[index]);
    } else {
        println!("Index out of bounds.");
    }
    

本文来自慕容云海的池塘