你可以在 MoonBit 中使用外部函数,通过 FFI 进行调用。
FFI
声明外部函数
你可以像这样声明一个外部函数:
func get_pi() -> Float = "math" "get_pi"
它与普通函数定义类似,只是函数体被两个字符串替换。
这两个字符串用于从Wasm导入对象中识别特定的函数,第一个字符串是模块名称,第二个字符串是函数名称。
声明之后,你可以像常规函数一样使用外部函数。
使用已编译的 Wasm
要使用已编译的Wasm,你必须在Wasm导入对象中提供所有声明的外部函数。
例如,要在上述代码片段中使用已编译的 Wasm,你需要将上面代码中的 my_wasm_func 添加到 Wasm 导入对象中,如下所示:
WebAssembly.instantiateStreaming(fetch("xxx.wasm"),{math: {get_pi: () => Math.PI}})
完整示例
让我们通过一个完整的示例来演示如何在 MoonBit 中使用 Convas API 绘制一个简单的笑脸。
draw.mbt
type Canvas_ctxfunc begin_path(self: Canvas_ctx) = "canvas" "begin_path"func arc(self: Canvas_ctx, x: Int, y: Int, radius: Int, start_angle: Float, end_angle: Float, counterclockwise: Bool) = "canvas" "arc"func move_to(self: Canvas_ctx, x: Int, y: Int) = "canvas" "move_to"func stroke(self: Canvas_ctx) = "canvas" "stroke"func get_pi() -> Float = "canvas" "get_pi"let pi: Float = get_pi()pub func draw(self: Canvas_ctx) {self.begin_path();self.arc(75, 75, 50, 0.0, pi * 2.0, true); // Outer circleself.move_to(110, 75);self.arc(75, 75, 35, 0.0, pi, false); // Mouth (clockwise)self.move_to(65, 65);self.arc(60, 65, 5, 0.0, pi * 2.0, true); // Left eyeself.move_to(95, 65);self.arc(90, 65, 5, 0.0, pi * 2.0, true); // Right eyeself.stroke();}
使用 moonc 编译该文件,以获取 draw.mbt.wasm。
moonc compile draw.mbtwat2wasm draw.mbt.wat
在 Javascript 中可以这样调用它
<html lang="en"><body><canvas id="canvas" width="150" height="150"></canvas></body><script>const spectest = {canvas: {stroke_rect: (ctx, x, y, width, height) => ctx.strokeRect(x, y, width, height),begin_path: (ctx) => ctx.beginPath(),arc: (ctx, x, y, radius, startAngle, endAngle, counterclockwise) => ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise),move_to: (ctx, x, y) => ctx.moveTo(x, y),stroke: (ctx) => ctx.stroke(),get_pi: () => Math.PI,},spectest: {print_i32: (x) => console.log(String(x)),print_f64: (x) => console.log(String(x)),print_char: (x) => console.log(String.fromCharCode(x)),},};const canvas = document.getElementById("canvas");if (canvas.getContext) {const ctx = canvas.getContext("2d");WebAssembly.instantiateStreaming(fetch("draw.wasm"), spectest).then((obj) => {obj.instance.exports._start()obj.instance.exports["Canvas_ctx::draw"](ctx);})}</script></html>
确保draw.mbt.wasm 和 index.html 在同一个文件夹中,然后在此文件夹中启动一个http服务器。例如,使用 Python:
python3 -m http.server 8080
在浏览器中访问 http://localhost:8080 ,应该会看到一个像这样的笑脸:

