本文介绍了如何在 WebAssembly 中从 Rust 返回一个字符串(或类似的)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从这个 Rust 代码创建了一个小的 Wasm 文件:

I created a small Wasm file from this Rust code:

#[no_mangle]
pub fn hello() -> &'static str {
    "hello from rust"
}

它构建并且可以从 JS 调用 hello 函数:

It builds and the hello function can be called from JS:

<!DOCTYPE html>
<html>
<body>
  <script>
    fetch('main.wasm')
    .then(response => response.arrayBuffer())
    .then(bytes => WebAssembly.instantiate(bytes, {}))
    .then(results => {
      alert(results.instance.exports.hello());
    });
  </script>
</body>
</html>

我的问题是 alert 显示未定义".如果我返回 i32,它会工作并显示 i32.我也尝试返回一个 String 但它不起作用(它仍然显示未定义").

My problem is that the alert displays "undefined". If I return a i32, it works and displays the i32. I also tried to return a String but it does not work (it still displays "undefined").

有没有办法在 WebAssembly 中从 Rust 返回字符串?我应该使用什么类型?

Is there a way to return a string from Rust in WebAssembly? What type should I use?

推荐答案

WebAssembly 仅支持少数 数字类型,这是所有可以通过导出函数返回的内容.

WebAssembly only supports a few numeric types, which is all that can be returned via an exported function.

当您编译为 WebAssembly 时,您的字符串将保存在模块的线性内存中.为了从托管 JavaScript 读取此字符串,您需要返回对其在内存中的位置的引用,以及字符串的长度,即两个整数.这允许您从内存中读取字符串.

When you compile to WebAssembly, your string will be held in the module's linear memory. In order to read this string from the hosting JavaScript, you need to return a reference to its location in memory, and the length of the string, i.e. two integers. This allows you to read the string from memory.

不管你编译成 WebAssembly 的语言是什么,你都使用同样的技术.如何从 WebAssembly 返回 JavaScript 字符串函数提供了问题的详细背景.

You use this same technique regardless of whichever language you are compiling to WebAssembly. How can I return a JavaScript string from a WebAssembly function provides a detailed background to the problem.

特别是对于 Rust,您需要使用外部函数接口 (FFI),使用 CString 类型,如下所示:

With Rust specifically, you need to make use of the Foreign Function Interface (FFI), using the CString type as follows:

use std::ffi::CString;
use std::os::raw::c_char;

static HELLO: &'static str = "hello from rust";

#[no_mangle]
pub fn get_hello() -> *mut c_char {
    let s = CString::new(HELLO).unwrap();
    s.into_raw()
}

#[no_mangle]
pub fn get_hello_len() -> usize {
    HELLO.len()
}

上面的代码导出两个函数,get_hello 返回字符串的引用,get_hello_len 返回字符串的长度.

The above code exports two functions, get_hello which returns a reference to the string, and get_hello_len which returns its length.

将上述代码编译成wasm模块后,可以按如下方式访问该字符串:

With the above code compiled to a wasm module, the string can be accessed as follows:

const res = await fetch('chip8.wasm');
const buffer = await res.arrayBuffer();
const module = await WebAssembly.compile(buffer);
const instance = await WebAssembly.instantiate(module);

// obtain the module memory
const linearMemory = instance.exports.memory;

// create a buffer starting at the reference to the exported string
const offset = instance.exports.get_hello();
const stringBuffer = new Uint8Array(linearMemory.buffer, offset,
  instance.exports.get_hello_len());

// create a string from this buffer
let str = '';
for (let i=0; i<stringBuffer.length; i++) {
  str += String.fromCharCode(stringBuffer[i]);
}

console.log(str);

C 等效的 可以在 WasmFiddle 中看到运行中.

这篇关于如何在 WebAssembly 中从 Rust 返回一个字符串(或类似的)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 07:37