更多是从一个前端开发者的角度,来比较一下两门语言的区别,以助于更方便的入门。

基本类型(DataType)

多数情况下,基本类型直接代表了最底层的语言实现。

JavaScript 是弱类型,基本数据类型有以下 7 种:

  • String
  • Number
  • BigInt
  • Boolean
  • Symbol ( ECMAScript 2016 新增 )
  • null
  • undefined

Rust 是 静态类型 ( statically typed ) 语言,也就是说在编译时就必须知道所有变量的类型。每一个值都属于某一个 数据类型 ( data type ),这告诉 Rust 它被指定为何种数据,以便明确数据处理方式。基本都属于两类数据类型子集:标量(scalar)和复合(compound)。

Integer (整数类型)

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

每一个有符号的变体可以储存包含从 $-(2^{n-1})$ 到 $2^{n-1}-1$ 在内的数字,这里 $n$ 是变体使用的位数。所以 i8可以储存从 $-(2^7)$ 到 $2^7-1$ 在内的数字,也就是从 $-128$ 到 $127$ 。无符号的变体可以储存从 $0$ 到 $2^n-1$ 的数字,所以 u8 可以储存从 $0$ 到 $2^8-1$ 的数字,也就是从 $0$ 到 $255$。

注意:可以使用以下表格的任何一种形式编写数字字面值。请注意可以是多种数字类型的数字字面值允许使用类型后缀,例如 57u8 来指定类型,同时也允许使用 _ 做为分隔符以方便读数,例如1_000,它的值与你指定的 1000 相同。

Integer 的表述方法

进制 案例
十进制 98_222
十六进制 0xff
八进制 0o77
二进制 0b1111_0000
字节(只表示 u8 型) b’A'

Floating-Point Number (浮点数字类型)

浮点数就是带小数点的数字。Rust 的浮点数类型是 f32和 f64,分别占 32 位和 64 位。默认类型是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。所有的浮点型都是有符号的。

Bool (布尔型)

标识:bool

  • true
  • false

Char(字符类型)

单引号标识字符类型 (char),双引号声明字符串 (str)。

Rust 的 char 类型的大小为四个字节(four bytes),并代表了一个 Unicode 标量值(Unicode Scalar Value),这意味着它可以比 ASCII 表示更多内容。在 Rust 中,拼音字母(Accented letters),中文、日文、韩文等字符,emoji(绘文字)以及零长度的空白字符都是有效的 char 值。Unicode 标量值包从 U+0000  到 U+D7FF 和 U+E000 到 U+10FFFF 在内的值。不过,「字符」 并不是一个 Unicode 中的概念,所以人直觉上的「字符」 可能与 Rust 中的 char 并不符合。

Compound types(复合类型)

Rust 有两个原生的复合类型:元组(tuple)和数组(array)。

  1. 元组是一个将多个其他类型的值组合进一个复合类型的主要方式。
    1. 元组长度固定:一旦声明,其长度不会增大或缩小。
  2. 数组中的每个元素的类型必须相同。
    1. Rust中的数组长度是固定的。

其他

  • Vector(Vec<T>
    • 可变长数组
    • Vector 允许我们在一个单独的数据结构中储存多于一个的值,它在内存中彼此相邻地排列所有的值
  • String
    • 字符串就是作为字节的集合外加一些方法实现的。
    • 称作 String 的类型是由标准库提供的,而没有写进核心语言部分,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。
  • Map(HashMap<K, V>
    • 它通过一个 哈希函数hashing function)来实现映射,决定如何将键和值放入内存中。很多编程语言支持这种数据结构,不过通常有不同的名字:哈希、map、对象、哈希表或者关联数组等等
    • 哈希 map 可以用于需要任何类型作为键来寻找数据的情况,而不是像 vector 那样需要通过索引。

变量(Variables)

var code = 123; // 在老版本的规范里面,只需要通过 var 关键字来声明
let firstName = "kaby"; // ES6 之后,let 表示变量,允许修改
const lastName = "Zhao"; // ES6 之后,const 表示是常量,不允许修改

firstName = "bike"; // 正常
lastName = "Hu"; // 报错 - Uncaught TypeError: Assignment to constant variable
// Rust 所有的变量默认都是不允许修改的,如
let code = 123; 
println!("The value of code is: {code}"); // 正常
code = 456; // 抛出错误 - cannot assign twice to immutable variable `code`

// 声明一个允许改变的变量
let mut name = "lulu";
println!("The name is: {name}"); // 输出 lulu
name = "jack";
println!("The name is: {name}"); // 输出 jack

// 同样可以声明常量的关键词
// 不允许对常量使用 mut
// 常量不光默认不能变,它总是不能变
const WAIT_SEC:u32 = 30;

// 变量隐藏
fn main() {
    let x = 5;
    let x = x + 1;
    {
        let x = x * 2;
				// 12
        println!("The value of x in the inner scope is: {x}");
    }
		// 6
    println!("The value of x is: {x}");
}

函数 & 逻辑

// 方法的声明
function getName() {
	return "jack";
}

// 通过变量的方式
let getInfo = function() {
	return {
		"age": 18
	}
}

// 上面也可以使用箭头表示
let getInfo = () => ({ "age": 18 })

// 逻辑
// 判断 if / switch
if (getName() == "jack") {
	return "lose";
} else if (getName() == "lose") {
	return "moth";
} else {
	return "";
}

// 循环 for...in / for...of / while
let arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++) {
	console.info(i);
}

// 可以看出来,JavaScript 因为是弱类型语言,会自动对变量类型进行推导和转化
// 所以对于一些比较和判断来说比较简单,直接通过 == 就可以
// 但是也会出现一些意外的情况,比如
// "5" == 5 的结果是 true,这边要多注意,可以通过 "5" === 5 解决。
// 也可以直接判断字符串是否相等
// "abc" == "cde"
// 方法
fn main() {
    println!("hello world");

    another_function();

    // print_labeled_measurement
    print_labeled_measurement(5, 'h');

    // plus_one
    let po = plus_one(8);
    // po == 9
    println!("计算结果是 {}", po);

    // do logic_info function
    logic_info("abc", 12);

    // loop
    loop_info();
}

// another_function
fn another_function() {
    println!("another_function");
}

// 带参数的方法
fn print_labeled_measurement(value: i32, unit_label: char) {
    println!("The measurement is: {value}{unit_label}");
}

// 如果这个方法有返回值的话,还需要定义返回值的类型
fn plus_one(x: i32) -> i32 {
    return x + 1;
}

// 逻辑判断
fn logic_info(name: &str, age: i32) {
    println!("{} 的年龄是 {} ", name, age);

    // 对于数字类型,可以直接使用 if 比较
    if age > 12 {
        println!("大于 12 岁,需要购买车票");
    } else if age < 12 {
        println!("免费乘车");
    } else {
        println!("12 岁,需要购买车票");
    }

    // 字符串的比较
    if name == "lulu" {
        println!("你好, {}", name);
    } else {
         println!("名字不匹配");
    }
}

// 循环
fn loop_info() {
    // while 循环
    let mut number = 3;
    while number != 0 {
        println!("{number}!");
        number -= 1;
    }
    println!("LIFTOFF!!!");

    // for 循环
    let a = [10, 20, 30, 40, 50];
    for element in a {
        println!("the value is: {element}");
    }

    // loop 循环
    // 注意,loop 循环不会自动终止,需要手动 break
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;
        }
    };
    println!("loop 循环结果是: {result}");
}

// 可以在这里查看具体的代码
// https://play.rust-lang.org/?gist=e87ef95f861dbc22bf8f23722e40aa34

—EOF—