You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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ß

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:00:27