过去属于死神,未来属于你自己。——雪莱
大家好,我是柒八九。
前言
最近,不是加大了对Rust
相关文章的输出吗,在评论区或者私信区。有一些不同的声音说:“Rust没有前途,然后...."。其实呢,看一个技术是否有需要学习的动力。想必大家的底层理由都是一切都是向钱看,毕竟在国内大家都是业务为主,想自己纯手搞一套符合自己的技术框架和范式,这是不切实际的。(当然也不能一杆子打死,还是有很多技术大牛的)现在大家纠结或者对这个技术属于观望态度,无非就是在平时开发工作中没有涉及到的点。
同时,由于国内技术的滞后性,有一些应用场景其实还是处于蛮荒的状态。(不是崇洋媚外,事实确实如此)。所以,在一些可以用到新的技术点的方向上,国内还是处于蓝海阶段。
所以,本着对该技术的独有关注度,我还是选择义无反顾的投身到学习和实际中。冲破黎明之前的黑暗,你会拥有太阳,而晨曦中第一缕阳光也是为你而耀眼。
而具体,Rust
到底能给你带来点啥,我们之前有文章讲过,这里就不在赘述了。
Last but not leaset
,由于现在本人暂时专注于前端领域居多,所以我更多关注Rust
能为前端带来点啥。而说到Rust
和前端,第一点的联想就是:WebAssembly
。(如果,不了解何为WebAssembly
,可以参考我们之前的文章浏览器第四种语言-WebAssembly,里面的例子是用Emscripten
写的)
其实,我们之前写过如何用C
写wasm
,也写过WebAssembly-C与JS互相操作等文章。但是,由于一些不可言喻的原因搁置了。
我们今天将使用Rust
创建一个WebAssembly Hello World
程序。我们将深入了解由wasm-bindgen
生成的代码,以及它们如何共同协作来帮助我们进行开发。我们还将使用wabt
来探索生成的wasm
代码。这将使我们更好地理解Rust WebAssembly
,并为我们的开发奠定良好的基础。
好了,天不早了,干点正事哇。
我们能所学到的知识点
- 前置知识点
- 项目搭建
- 原理探析
- 内容拓展
1. 前置知识点
前置知识点,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。如果大家对这些概念熟悉,可以直接忽略
同时,由于阅读我文章的群体有很多,所以有些知识点可能我视之若珍宝,尔视只如草芥,弃之如敝履。以下知识点,请酌情使用。
安装Rust
如果是你一个Rust
萌新,我们也给你提供Rust环境配置和入门指南。
如果,想独立完成安装,可以到Rust 安装页面跟着教程安装。
在安装成功Rust
后,它会安装一个名为rustup
的工具,这个工具能让我们管理多个不同版本的 Rust
。默认情况下,它会安装用于惯常 Rust
开发的 stable
版本 Rust Release
。
Rustup
会安装
Rust
的编译器rustc
Rust
的包管理工具cargo
Rust
的标准库rust-std
- 以及一些有用的文档
rust-docs
因为,我本机已经安装好了Rust
。我们可以通过rustup --version
来查看rustup
的版本。以下是我本机的rustup
版本信息。下文中所有的代码,都基于该版本。
rustup --version rustup 1.26.0 (5af9b9484 2023-04-05)
安装WebAssembly二进制工具包(wabt)
这些工具旨在用于开发工具链或其他系统,这些系统希望操作WebAssembly文件。与WebAssembly
规范解释器不同(该解释器旨在尽可能简单、声明性和“规范性”),这些工具是用C/C++
编写的,并设计成更容易集成到其他系统中。这些工具不旨在提供优化平台或更高级的编译目标;相反,它们旨在实现与规范的完全适应和遵从。
我们可以利用brew
来在Mac
环境下安装。
2. 项目搭建
2.1 安装wasm-bindgen
我们可以通过cargo install --list
来查看在$HOME/.cargo/bin
位置安装过的Rust
二进制文件。
在一些其他的教程中可以不使用wasm-bindgen
构建Hello World
程序,但是在本文中,我们将使用它,因为它在Rust WebAssembly
开发中是必不可少的。
cargo install wasm-bindgen-cli
Rust WebAssembly
允许我们将WebAssembly模块
有针对性地插入到现有的JavaScript
应用程序中,尤其是在性能关键的代码路径中。我们可以将wasm-bindgen
视为一种工具,它通过生成用于JavaScript
和WebAssembly
之间高效交互的粘合代码和绑定来帮助我们实现丝滑的交互体验。
2.2 创建Rust WebAssembly项目
巴拉拉小魔仙,念诵如下咒语,构建一个Rust WebAssembly
项目。
cargo install wasm-bindgen-cli
上面的代码是使用Cargo
工具创建一个新的Rust
项目,项目的名称是hello_world
,并且指定它是一个库(--lib
)。这将创建一个包含基本项目结构的文件夹,其中包括一个Cargo.toml
文件和一个src
文件夹。
+-- Cargo.toml +-- src +-- lib.rs
Cargo.toml
文件用于管理项目的依赖和配置src
文件夹包含项目的Rust源代码文件
- 项目名称
hello_world
是一个示例名称,我们可以根据自己的需求为项目指定不同的名称。
2.3 修改Cargo.toml
配置项
使用宇宙最强IDE -VScode
,打开Cargo.toml
文件。我们应该会看到以下内容。
[package] name = "hello_world" version = "0.1.0" authors = ["789"] edition = "2021" [dependencies]
将其修改成下面的内容
[package] name = "hello_world" version = "0.1.0" authors = ["789"] edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
上面的大部分字段大家都能看懂,其中lib
项的配置,这里稍微解释一下:
crate-type = ["cdylib"]
: 这一行指定了生成的库的类型。在这里,crate-type
设置为["cdylib"]
,这表示我们正在创建一个动态链接库(C-compatible dynamic library
)。这用于编译一个供其他编程语言加载的动态库。此输出类型将在Linux
上创建*.so
文件,在macOS
上创建*.dylib
文件,在Windows
上创建*.dll
文件。
这种类型的库可以被其他编程语言调用,因为它们与C语言兼容。这对于与WebAssembly(Wasm)互操作性很重要,因为Wasm
通常需要与C语言
接口进行交互。因此,cdylib
表示该库是一个可供其他语言使用的动态链接库
。
2.4 编辑lib.rs
打开src/lib.rs
文件。将其更改为以下内容:
extern crate wasm_bindgen; use wasm_bindgen::prelude::*; // 导入 'window.alert' #[wasm_bindgen] extern "C" { fn alert(s: &str); } // 导出一个 'helloworld' 函数 #[wasm_bindgen] pub fn helloworld(name: &str) { alert(&format!("Hello World : {}!", name)); }
我们简单解释一下核心代码:
extern crate wasm_bindgen;
: 这一行声明了对wasm_bindgen
库的依赖。wasm_bindgen
是一个Rust库,用于构建Wasm
模块并提供与JavaScript
的互操作性。在Rust
当中,库被称为crates
,因为我们使用的是一个外部库,所以有extern
。use wasm_bindgen::prelude::*;
: 这一行导入了wasm_bindgen
库的预导出(prelude
)模块中的所有内容,以便在后续代码中使用。
在 Rust 中调用来自 JavaScript 的外部函数
#[wasm_bindgen] extern "C" { fn alert(s: &str); }
#[wasm_bindgen]
: 在 #[]
中的内容叫做 "属性",并以某种方式改变下面的语句。#[wasm_bindgen]
是一个属性标记,用于指定与WebAssembly
互操作相关的特性。
extern "C" { fn alert(s: &str); }
: 这里声明了一个外部函数alert
,它使用extern "C"
指定了C ABI
(应用二进制接口),这意味着它可以与C语言进行交互。这个alert
函数没有在Rust
中实现,而是在JavaScript
中实现,用于在浏览器中显示警告框。
在 JavaScript 中调用的 Rust 函数
#[wasm_bindgen] pub fn helloworld(name: &str) { alert(&format!("Hello World : {}!", name)); }
#[wasm_bindgen] pub fn helloworld(name: &str)
: 这是一个Rust
函数helloworld
,它被标记为wasm_bindgen
,这意味着它可以被JavaScript
调用。这个函数接受一个字符串参数name
,然后调用之前声明的alert
函数,以显示带有Hello World
消息的弹框,并在消息中包括name
参数的内容。
2.5 编译代码
在命令行中输入以下命令:
cargo build --target wasm32-unknown-unknown
如果未安装对应的库,控制台会给出提示。
那我们就照猫画虎的操作一下:
bash
复制代码
rustup target add wasm32-unknown-unknown
cargo build
: 这是Cargo
工具的命令,用于构建Rust
项目。它会编译项目的源代码并生成可执行文件或库文件,具体取决于项目的类型。--target wasm32-unknown-unknown
: 这部分是构建的目标参数。--target
标志用于指定要构建的目标平台。在这里,wasm32-unknown-unknown
是指定了WebAssembly
目标平台。这告诉Cargo
生成适用于WebAssembly
的二进制文件,而不是生成本地平台的二进制文件。
当运行这个命令后,Cargo
会使用 Rust
编译器(Rustc
)以及与 WebAssembly
相关的工具链,将 Rust
代码编译为 WebAssembly
格式的二进制文件。这个生成的 Wasm
文件可以在浏览器中运行,或与其他支持 WebAssembly
的环境一起使用。
运行结果如下:
cargo build --target wasm32-unknown-unknown
命令的默认输出位置是在项目的 target
目录下,具体位置是:
target/wasm32-unknown-unknown/debug/
在这个目录下,我们会找到生成的 WebAssembly
文件(通常是一个 .wasm
文件),以及其他与编译过程相关的文件。