keywords: Rust, 交互, C 语言, Python, Node.js, WebAssembly


在现代软件开发中,语言间的互操作性变得越来越重要。Rust 以其安全性、高性能和并发性著称,但在某些情况下,我们仍需要与其他编程语言进行交互。本章将详细探讨 Rust 如何与 C 语言、Python、Node.js 和 Java 进行交互,以及如何利用 Rust 和 WebAssembly 开发高效的 Web 应用。

与 C 语言交互

Rust 提供了强大的 FFI(Foreign Function Interface),使得与 C 语言的交互变得相对简单。我们可以用 Rust 调用 C 函数,也可以用 C 语言调用 Rust 函数。

调用 C 函数

首先,让我们来看一个简单的例子,演示如何在 Rust 中调用 C 语言函数。假设我们有一个 C 的共享库 mathlib,其中提供了一个函数 add

  1. // mathlib.c
  2. #include <stdio.h>
  3. int add(int a, int b) {
  4. return a + b;
  5. }

接下来,我们需要用 bindgen 工具生成 Rust 的绑定:

  1. $ bindgen mathlib.h -o src/bindings.rs

生成的 bindings.rs 文件如下:

  1. // bindings.rs
  2. #[link(name = "mathlib")]
  3. extern "C" {
  4. pub fn add(a: i32, b: i32) -> i32;
  5. }

然后,我们可以在 Rust 中调用这个 add 函数:

  1. // main.rs
  2. mod bindings;
  3. fn main() {
  4. unsafe {
  5. let result = bindings::add(5, 3);
  6. println!("The result of adding 5 and 3 is: {}", result);
  7. }
  8. }

调用 Rust 函数

同样地,我们也可以从 C 语言调用 Rust 函数。首先,我们定义一个 Rust 函数:

  1. // lib.rs
  2. #[no_mangle]
  3. pub extern "C" fn multiply(a: i32, b: i32) -> i32 {
  4. a * b
  5. }

然后,在 C 程序中,我们可以调用这个 Rust 函数:

  1. // main.c
  2. #include <stdio.h>
  3. extern int multiply(int a, int b);
  4. int main() {
  5. int result = multiply(4, 2);
  6. printf("The result of multiplying 4 and 2 is: %d\n", result);
  7. return 0;
  8. }

与 Python 交互

为了在 Python 中使用 Rust 代码,我们可以利用 PyO3 库。PyO3 是一个使得 Rust 与 Python 互操作的库。

使用 PyO3 创建 Python 模块

首先,我们需要添加 PyO3 依赖:

  1. # Cargo.toml
  2. [dependencies]
  3. pyo3 = { version = "0.15", features = ["extension-module"] }

接下来,我们可以编写 Rust 代码以创建一个 Python 扩展模块:

  1. // lib.rs
  2. use pyo3::prelude::*;
  3. #[pyfunction]
  4. fn sum_as_string(a: i32, b: i32) -> PyResult<String> {
  5. Ok((a + b).to_string())
  6. }
  7. #[pymodule]
  8. fn rust_extension(py: Python, m: &PyModule) -> PyResult<()> {
  9. m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
  10. Ok(())
  11. }

然后,我们需要创建一个 setup.py 文件以便构建这个 Python 模块:

  1. # setup.py
  2. from setuptools import setup
  3. from setuptools_rust import RustExtension
  4. setup(
  5. name="rust_extension",
  6. version="0.1",
  7. rust_extensions=[RustExtension("rust_extension.rust_extension", "Cargo.toml", binding="pyo3")],
  8. packages=["rust_extension"],
  9. zip_safe=False,
  10. )

最后,运行以下命令以构建并安装这个模块:

  1. $ python setup.py install

现在,我们可以在 Python 中使用这个模块:

  1. import rust_extension
  2. result = rust_extension.sum_as_string(5, 7)
  3. print(f"The result is: {result}")

与 Node.js 交互

为了在 Node.js 中使用 Rust 代码,我们可以利用 neon 库。neon 是一个用于编写 Node.js 原生模块的库。

使用 neon 创建 Node.js 模块

首先,安装 neon CLI 工具:

  1. $ npm install -g neon-cli

然后,初始化一个新的 Neon 项目:

  1. $ neon new my-project
  2. $ cd my-project

在生成的项目中,我们可以编写 Rust 代码以创建一个 Node.js 扩展模块:

  1. // src/lib.rs
  2. use neon::prelude::*;
  3. fn add(mut cx: FunctionContext) -> JsResult<JsNumber> {
  4. let a = cx.argument::<JsNumber>(0)?.value(&mut cx);
  5. let b = cx.argument::<JsNumber>(1)?.value(&mut cx);
  6. Ok(cx.number(a + b))
  7. }
  8. register_module!(mut cx, {
  9. cx.export_function("add", add)
  10. })

然后,运行以下命令以构建并安装这个模块:

  1. $ neon build

现在,我们可以在 Node.js 中使用这个模块:

  1. const myAddon = require("./native");
  2. console.log(myAddon.add(3, 4)); // 输出: 7

与 Java 交互

为了在 Java 中使用 Rust 代码,我们可以利用 JNI(Java Native Interface)。

使用 JNI 创建 Java 本地库

首先,我们需要在 Java 中声明一个本地方法:

  1. // Main.java
  2. public class Main {
  3. static {
  4. System.loadLibrary("rustlib");
  5. }
  6. public native int multiply(int a, int b);
  7. public static void main(String[] args) {
  8. Main main = new Main();
  9. int result = main.multiply(4, 3);
  10. System.out.println("The result of multiplying 4 and 3 is: " + result);
  11. }
  12. }

接下来,在 Rust 中实现这个本地方法:

  1. // lib.rs
  2. #[no_mangle]
  3. pub extern "system" fn Java_Main_multiply(env: *mut JNIEnv, class: jclass, a: jint, b: jint) -> jint {
  4. a * b
  5. }

然后,使用 javac 编译 Java 文件并生成 JNI 头文件:

  1. $ javac Main.java
  2. $ javah -jni Main

最后,使用 cargo 构建 Rust 库:

  1. $ cargo build --release

确保将生成的 .so 文件放在正确的位置,然后运行 Java 程序:

  1. $ java Main

Rust 和 WebAssembly

最后,我们来看看如何将 Rust 编译成 WebAssembly,并在浏览器中使用它。WebAssembly 提供了一种高效的方式来运行 Rust 代码,并且与 JavaScript 互操作性良好。

编写和编译 WebAssembly

首先,我们需要安装 wasm-pack 工具:

  1. $ cargo install wasm-pack

然后,创建一个新的 Rust 项目并添加 WebAssembly 支持:

  1. $ cargo new --lib wasm_project
  2. $ cd wasm_project

Cargo.toml 中,添加 WebAssembly 相关依赖:

  1. [dependencies]
  2. wasm-bindgen = "0.2"
  3. [lib]
  4. crate-type = ["cdylib"]

编写 Rust 代码以创建一个简单的 WebAssembly 模块:

  1. // src/lib.rs
  2. use wasm_bindgen::prelude::*;
  3. #[wasm_bindgen]
  4. pub fn greet(name: &str) -> String {
  5. format!("Hello, {}!", name)
  6. }

然后,运行以下命令以编译 WebAssembly 模块:

  1. $ wasm-pack build --target web

在浏览器中使用 WebAssembly

创建一个 HTML 文件来使用这个 WebAssembly 模块:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>Rust and WebAssembly</title>
  6. <script type="module">
  7. import init, { greet } from "./pkg/wasm_project.js";
  8. async function run() {
  9. await init();
  10. console.log(greet("World"));
  11. }
  12. run();
  13. </script>
  14. </head>
  15. <body></body>
  16. </html>

然后,用浏览器打开这个 HTML 文件,你将看到控制台中输出 Hello, World!

通过这些示例,我们看到 Rust 提供了丰富的工具和库,方便与其他编程语言进行交互,使得我们可以在不同的项目中充分利用 Rust 的优势。