如何使用bun:ffi读取Rust返回的复杂结构体指针数据?
解决Bun FFI读取Rust返回结构体指针的问题
先修正基础问题,再逐步实现结构体数据的读取:
1. 修正TypeScript函数调用参数
你的TypeScript代码调用complex()时未传入left和right参数,会导致Rust函数拿到错误参数值,先补上:
const left = 10; const right = 2; const pointer = lib.symbols.complex(left, right); // 传入正确的运算参数
2. 在Bun FFI中定义对应结构体类型
Rust的SimResult用了#[repr(C)]保证内存布局与C结构体一致,你需要在TypeScript里用Bun.FFI.Struct定义完全匹配的结构体类型:
import { dlopen, FFIType, Struct } from "bun:ffi"; // 与Rust端SimResult一一对应的C结构体类型 const SimResult = new Struct({ add: FFIType.isize, // 对应Rust的isize类型 subtract: FFIType.isize, divide: FFIType.f64, // 对应Rust的f64类型 });
3. 从指针读取结构体数据
拿到指针后,调用指针的read()方法并传入定义好的结构体类型,即可解析出完整数据:
// 读取指针指向的结构体内容 const result = pointer.read(SimResult); // 验证结果 console.log(`加法结果: ${result.add}`); console.log(`减法结果: ${result.subtract}`); console.log(`除法结果: ${result.divide}`);
4. 必须处理:释放Rust分配的内存
你在Rust里用Box::new分配了堆内存,这块内存不会被Bun自动回收,必须手动释放避免内存泄漏。需要补充Rust代码并在TypeScript中调用:
补充Rust的内存释放函数
#[no_mangle] pub extern "C" fn free_sim_result(ptr: *mut SimResult) { unsafe { // 将指针转换回Box,让Rust自动完成内存释放 let _ = Box::from_raw(ptr); } }
在TypeScript中调用释放函数
更新dlopen的符号定义,添加free_sim_result,并在使用完结构体后调用:
const lib = dlopen(path, { complex: { args: [FFIType.isize, FFIType.isize], // 修正:原代码用i32,需与Rust的isize对应 returns: FFIType.ptr, }, free_sim_result: { args: [FFIType.ptr], returns: FFIType.void, } }); // ...读取结构体之后 lib.symbols.free_sim_result(pointer);
完整TypeScript示例代码
import { dlopen, FFIType, Struct } from "bun:ffi"; import path from "path"; // 替换为你的Rust编译生成的动态库路径 const libPath = path.resolve("./libyour_rust_lib.so"); // 定义结构体类型 const SimResult = new Struct({ add: FFIType.isize, subtract: FFIType.isize, divide: FFIType.f64, }); const lib = dlopen(libPath, { complex: { args: [FFIType.isize, FFIType.isize], returns: FFIType.ptr, }, free_sim_result: { args: [FFIType.ptr], returns: FFIType.void, } }); // 调用函数并读取结果 const left = 15; const right = 3; const pointer = lib.symbols.complex(left, right); const result = pointer.read(SimResult); console.log("计算结果:", result); // 输出示例:计算结果: { add: 18, subtract: 12, divide: 5 } // 释放内存 lib.symbols.free_sim_result(pointer);
关键注意事项
- Rust结构体的
#[repr(C)]不能省略,否则内存布局不固定,TypeScript无法正确解析。 - TypeScript结构体的字段顺序、类型必须与Rust完全一致,否则会读取到错误数据。
- 内存释放是必做步骤,长期运行的程序若不释放会导致内存占用持续增长。
内容的提问来源于stack exchange,提问作者Johannes Klauß
相关产品推荐
相关产品推荐

