前端同学的rust入门(二): rust基础类型

2,685 阅读7分钟

概述

本文已经预设你是一个JS老手了。 我们先来比较一下JS和Rust的区别。

编译型语言和解释型语言的差异

我们都知道cpu是无法直接执行高级语言的,为了能让高级语言执行起来,就需要一个翻译官,将其转换为cpu能识别的机器码。 翻译就有三种方式: 1.先把所有代码翻译好,然后将机器码交给cpu执行,这种被称为编译型语言,它在执行之前,需要经过编译器进行编译。比如C/C++。 2.代码被放到一个解释器中执行,解释器在执行代码的过程中,即时的将代码转换为机器码,这种被称为解释型代码,它是边执行边转换的。比如JS和Python。 3.第三种,则是结合了编译和解释的方式。先使用编译方式进行生成中间码,然后在执行时使用运行时或者虚拟机解释中间码。比如Java和C#

这三种方式各有优缺点,这里就不一一展开来说了。 rust属于编译型语言,它的使用方式跟JS大为不同。 编译型语言是没有运行时的,相反的JS的运行时就是V8,Java的是JVM,C#的是CLR。这些虚拟机能帮开发者做很多事情,其中一项就是内存管理。 所谓内存的管理,主要就是内存的分配和回收。 在JS中,不用关心内存,你也可能写出流畅的代码,即使可能带来一点内存泄漏,但是也不太容易造成程序崩溃。 rust就不一样了,你需要非常关心内存。一定意义上来讲,rust让你更加贴近程序的本质:计算机里一切皆内存。

从开发体验上来讲,JS最大的特点是灵活,而rust对应的就是僵硬。当从JS切换到TS时,可能很多人已经会有这样的体验了,但是rust会比TS更加僵硬,尤其是在数据类型上。这种僵硬是编译型语言所必须的---编译是在代码执行前进行的,编译器需要保证一切数据结构是确定的,并且是稳定的,不会在运行时被更改。 Rust语言的设计精髓之一就是:确定性。

看一个demo

先看一个官方的demo,体会一下跟JS有什么不同。 注意,代码是需要用命令行或者终端执行启动命令的。 这段代码的作用是:

  1. 生成一个随机数让用户猜测
  2. 然后监听命令行,看用户在命令行输入了什么数字
  3. 将用户输入的数字与随机数对比,看是否相等
  4. 打印对比的结果
use std::io; //use是包引用,它的含义等同于 import {io} from 'std'。'std'是标准库,无需额外安装。
use rand::Rng; //同上一行,这个包用来生成随机数

fn main() {//这里有一个main函数,与JS不同。rust程序必须有且只有一个main函数,它是程序的入口。运行程序后执行的第一个函数,一定是main函数。
    println!("Guess the number!");//等同于console.log

    let secret_number = rand::thread_rng().gen_range(1..101);// 这里生成了一个1~100的随机数

    println!("The secret number is: {}", secret_number);

    println!("Please input your guess.");

    
    let mut guess = String::new();//声明了一个String数据,注意有个mut。我们后面讲它的含义

    io::stdin().read_line(&mut guess)//监听用户的输入,并将输入值赋值给guss变量。注意&mut,我们后面讲它的含义。
        .expect("Failed to read line");//异常处理

    let guess: u32 = guess.trim().parse()//使用了将guess的字符串值转变成数字,并赋值给一个新的guess变量,但是数据类型是u32的
        .expect("Please type a number!");

    println!("You guessed: {}", guess);
    match guess.cmp(&secret_number) {   //对数据进行对比
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => println!("You win!"),
    }
}

这个程序里,有一些跟JS很像,即使不了解rust语法,也能猜出来个大概。但是有一些语法就看不懂了,不要急,我们慢慢来。 先看一下rust的基础类型:

类型

JS中的数据类型分为原始类型和object两个大类。 Rust类似的,也分了两类,基础类型和复合类型。 基础类型对应原始类型,复合对应object类型。

基础类型

基础类型包含整数、浮点数、布尔类型和字符类型。

整数/浮点数

在JS中只有number类型,不区分整数和浮点数。 但是Rust的是区分的,而且分的非常细。 看一个rust的声明:

 let x:u8=100;
 let y: f32 = 3.0;

这里面u8表示的意思是'无符号的8位整数',我们解释一下这句话:

  1. 无符号表示的正整数,有符号表示的是可以为负数。数字在内存中最终是以二进制表示的,符号就指的是二进制的第一位数字是否为1.

  2. 8表示的是位数,位数指的是内存的寻址空间。8位表示是这个整数类型,最多能容纳2的7次方-1的值,也就是0~255。这里要注意,如果给一个u8类型赋值超过255,就会报错。

  3. 如果使用了有符号类型,就只能表示'-128 到 127' 。体会一下区别 4.rust支持的整数类型如下: 长度 | 有符号 | 无符号 | | ------- | ------- | ------- | | 8-bit | i8 | u8 | | 16-bit | i16 | u16 | | 32-bit | i32 | u32 | | 64-bit | i64 | u64 | | 128-bit | i128 | u128 | | arch | isize | usize |

  4. 浮点数简单一点,只有f32和f64。f32是单精度浮点数,f64则是双精度浮点数。

  5. 数值类型的使用,加减乘除取余则跟JS一致。

布尔类型

与JS一致。

字符类型

这里要注意,JS中有string类型,但是没有字符类型的。字符类型的关键字是'char'。 内存对char和string的处理方式是不同的。 rust声明字符是这样的:

    let c = 'z';
    let z = 'ℤ';
    let heart_eyed_cat = '😻';

注意:1. 它是单引号的。'z'和"z"虽然都只有一个z,但是前者是char,后者是string。是两种不同的数据类型
2. char只能是单个字符,'ws'这种样式的赋值是无效的
3. char表示的是Unicode标量值,它能表示中文,拼音,韩文,emoji等不同类型的内容

函数

函数的写法类似TS,比较易懂。

fn add(i: i32, j: i32) -> i32 {
  i + j 
}

这段代码声明了一个函数,对于函数的参数和返回值都需要明确标识类型。 但是我们发现,这个函数没有return; 实际上rust引入了一个表达式的概念,它的作用等同于 retrun i+j;我们比较一下

return  i+j; //正常的return 语句,有;
i+j  //表达式,没有;

表达式可以搭配作用域,实现一种奇特的效果:

fn main() {
    let y = {
        let x = 3;
        x + 1
    };

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

匿名函数

rust中对匿名函数有另外的叫法,叫闭包。它与js的箭头函数异曲同工:

// js箭头函数
const  a =1;
const add =()=>{
return  a+1;
}

//rust匿名函数
let x = 3; 
let add = |a| a  + x ; //注意看语法,使用|a|达到了js中(a)=>的效果
let res =add(1)

综述

以上就是rust中比较常见的基础类型了,看起来并不算难。 下一章,我们会讨论rust中的一个复杂的概念“可变和不可变”