查看原文
其他

写给javascript程序员的rust教程(二)变量与数据类型【译】

coolder117 码农真经 2023-12-25

这是写给javascript程序员的rust教程系列文章的第二部分:变量与数据类型。

第一部分见:写给javascript程序员的rust教程(一)工具链概述【译】

变量

JavaScript有三种声明变量的方法:var,const和let。Rust也有const和let,但与JavaScript相比,它们的工作方式截然不同。

let

在rust中,用let 声明 变量:

let a = 123;

正如预期的那样,这将为变量 a 分配 123 的值。但默认情况下 ,Rust 变量不可更改,也就是说在赋值之后,你将无法改变它的值。

let a = 123;
a = 456; // Error! 🙁

乍一看,这与JavaScript的const类似,但JavaScript的const并不能使变量不可变,它只是使绑定不可变。

如果你想让变量可变,你需要使用mut关键字显式地声明。

let mut a = 123;
a = 456; // No Error 🙂

const

Rust的const与JavaScript的const也有很大的不同–最好把Rust的const看成是一个常量值的 “标签”。在编译时,它们在所有被使用的地方都会被它们的实际值取代。它通常用于端口号、超时值、错误代码等常量。

你也可以在全局级别定义const外部函数,这是用let做不到的。


数据类型

数值

在JavaScript中,我们同时具有数字类型(整数(无小数点的数字)和浮点数(有小数点的数字))。

在Rust中,整数和浮点数有很多选择,但默认情况下,我们可以将i32用作整数,将f64用作浮点数。

let x = 123; // i32
let y = 4.5; // f64

布尔值

非常简单-JavaScript和Rust都具有带有true / false值的布尔值。

let x = false; // bool

字符串

在使用JavaScript时,我们通常不会过多考虑字符串-它们总是可以“正常工作”。在Rust中,字符串的类型有很多种,其中被广泛使用的字符串是:String和&str。

String是可变长的,&str 是定长的。

当你使用字符串字面量创建字符串,该字符串默认为&str类型。

let name = "Saitama"; // &str

可以使用String::from 或 t0_string 方法创建String 类型字符串。

let name = String::from("Genos"); // String
let name2 = "King".to_string(); // String

通过 as_str 函数可以将 String 类型转化成 &str 类型。

let name2 = "King".to_string(); // String
let name3 = name2.as_str(); // &str

关于字符串,后续文章会进一步讨论。


Optionals

JavaScript的空值有两种类型–undefined和null。undefined是指变量、属性等未被定义,而null则是指故意为空。

Rust 完全没有这些–它甚至没有一个专门的 null 数据类型。与之替代,它有一个叫做Option的东西。当我们遇到一个值可能为空或初始未定义的情况时,就会使用这个 Option 类型。

使用过TypeScript/Flow的人可能会发现这里有一些相似之处,但在如何创建和使用optionals方面却有很大不同。

假设我们想写一个函数,接收一个文件路径并返回其内容。并且要求当空字符串作为文件路径传递时,我们想返回一个 “null “值。

下面是我们在JavaScript/TypeScript中的写法:

function read_file(path: string): string | null {
const contents = "hello";

if (path !== "") {
return contents;
}

return null;
}

Rust 通过 Option 完成相同的操作:

fn read_file(path: &str) -> Option<&str> {
let contents = "hello";

if path != "" {
return Some(contents);
}

return None;
}

你可以看到,对于空值,我们返回None,但对于非空值,我们并没有原封不动地返回内容,而是将其 “包裹 “在Some里面并返回。返回类型也不是TypeScript例子中的 “string或null”,而是 “Option that contains &str “类型。

下面是你在JavaScript/TypeScript中调用read_file这个函数的方式:

function main() {
const file_contents = read_file("/path/to/file");

if (file_contents !== null) {
console.log(file_contents); // file_contents is refined to string type
} else {
console.log("Empty!");
}
}

Rust 调用方式:

fn main() {
let file = read_file("path/to/file");

if file.is_some() {
let contents = file.unwrap();
println!("{}", contents);
} else {
println!("Empty!");
}
}

如你所见,我们需要手动 “拆开 “Option来获取里面的内容。


数组

与字符串类似,Rust有两种类型的数组–一种是固定大小的数组(简称为 “Array”),另一种是可以增长/收缩大小的数组(称为 “Vectors”)。

Arrays

fn main() {
let list = [1, 2, 3];
println!("{:?}", list);
}

Vectors

fn main() {
let mut list = vec![1, 2, 3];
list.push(4);
println!("{:?}", list);
}

对象

从技术上讲,所有的非原生类型在JavaScript中都是 “对象”,但我们通常使用 “对象 “一词来做两件事–Bag of data (数据包) 和hashmap(hash字典)。

Bag of data (数据包)

与其他语言不同的是,JavaScript最酷的地方,你不需要经过很多仪式来创建一个对象。比如,要在JavaScript中创建一个雇员对象:

function main() {
const employee = {
name: "Saitama",
age: 25,
occupation: "Hero",
};
}

Rust创建类似javascript的对象,需要用到struct:

struct Employee {
name: String,
age: i32,
occupation: String,
}

fn main() {
let employee = Employee {
name: "Saitama".to_string(),
age: 25,
occupation: "Hero".to_string(),
};
}

HashMap

在JavaScript中,要创建具有任意键值对的对象,我们可以使用对象字面量或Map对象:

function main() {
const colors = new Map();

colors.set("white", "#fff");
colors.set("black", "#000");

console.log(colors.get("white")); // #fff
}

Rust 可以使用HashMap类型实现:

use std::collections::HashMap;

fn main() {
let mut colors = HashMap::new();

colors.insert("white".to_string(), "#fff");
colors.insert("black".to_string(), "#000");

println!("{:?}", colors.get("white").unwrap()); // #fff
}

请注意上面 unwrap 的用法。HashMap的get方法返回的是一个Option类型,我们需要对这个Option类型进行解包来获取里面的值。

谢谢你的阅读 🙂

继续滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存