你可以在 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_ctx
func 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 circle
self.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 eye
self.move_to(95, 65);
self.arc(90, 65, 5, 0.0, pi * 2.0, true); // Right eye
self.stroke();
}
使用 moonc 编译该文件,以获取 draw.mbt.wasm。
moonc compile draw.mbt
wat2wasm 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 ,应该会看到一个像这样的笑脸: