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

如何在Rust FFI中正确解析数组类型参数?我的实现解析失败

Rust FFI 数组参数解析错误的修复方案

问题根源

你定义的FfiArray是C风格的数组元组结构体(包含数据指针和长度),但Node.js端直接传递了DoubleArray类型——这是把数组的原始内存直接传给Rust,和Rust期望的结构体内存布局完全不匹配。所以Rust会把数组第一个元素的二进制值(1.2的IEEE754表示0x3ff3333333333333)当成data指针,把后续内存里的随机值当成len,导致解析完全错误。

修复步骤

1. 统一两端的参数类型(Node.js端)

在Node.js里定义和RustFfiArray完全对应的C结构体,手动传入数组的指针和长度:

import ffi from "ffi-napi";
import ref from "ref-napi";
import ref_struct from "ref-struct-di";

const StructType = ref_struct(ref);

// 定义和Rust FfiArray完全匹配的C结构体
const FfiArray = StructType({
  data: ref.refType(ref.types.double), // 对应Rust的*const f64
  len: ref.types.size_t // 对应Rust的usize
});

const libm = ffi.Library("./target/release/wave_from_tools.dll", {
  my_push: ["void", [FfiArray]] // 参数类型改为自定义的FfiArray结构体
});

// 创建测试数组,需确保数组在函数调用期间不会被GC回收
const testArr = new Float64Array([1.2, 2.2]);
// 包装成FfiArray结构体
const ffiArr = new FfiArray();
ffiArr.data = testArr.buffer;
ffiArr.len = testArr.length;

libm.my_push(ffiArr);

2. 完善Rust端的slice转换(可选但推荐)

在Rust函数里把FfiArray转换成安全的&[f64]切片,方便后续处理:

use safer_ffi::{prelude::*};

#[derive_ReprC]
#[repr(C)]
#[derive(Debug)]
pub struct FfiArray<'a> {
    pub data: *const f64,
    pub len: usize,
    _marker: std::marker::PhantomData<&'a [f64]>,
}

#[ffi_export]
pub fn my_push(array: FfiArray) {
    // 转换成安全切片,需确保data指针有效且len正确
    let slice = unsafe { std::slice::from_raw_parts(array.data, array.len) };
    println!("my_push: 数组内容: {:?}, 长度: {}", slice, array.len);
}

3. 复杂结构体数组的扩展(针对[{ idx: 2, name: "test_name" }]场景)

如果要传递自定义结构体数组,步骤类似:

  • Rust端定义带#[derive_ReprC]的结构体
  • Node.js端定义对应的结构体类型,再创建结构体数组,最后包装成FfiArray传递

示例Rust代码:

#[derive_ReprC]
#[repr(C)]
#[derive(Debug)]
pub struct FfiItem {
    pub idx: u32,
    pub name: *const c_char, // 用C风格字符串传递文本
}

#[derive_ReprC]
#[repr(C)]
#[derive(Debug)]
pub struct FfiItemArray<'a> {
    pub data: *const FfiItem,
    pub len: usize,
    _marker: std::marker::PhantomData<&'a [FfiItem]>,
}

Node.js端对应定义结构体后,即可按同样逻辑创建数组并传递。

关键注意事项

  • 内存安全:确保Node.js传递的数组在Rust函数执行期间不会被JavaScript引擎GC回收,避免悬垂指针。
  • 类型匹配:两端的结构体字段类型、顺序必须完全一致,否则会出现内存解析错位。
  • 字符串处理:传递字符串时需用C风格的const char*(Rust用safer_ffi::str::CStr),不能直接传JavaScript字符串。

内容的提问来源于stack exchange,提问作者tomato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:55:09