如何在Go中使用一个切片作为参数调用Rust函数?

8

我希望能够使用一个切片的引用,从Go语言中调用一些用Rust编写的外部函数。

我有以下的Rust代码:

extern crate libc;

#[no_mangle]
pub extern "C" fn callme(data: &mut [libc::c_double]) -> i32 {
    data.len() as i32
}

该函数可通过此C风格头文件为cgo编译器提供。
#IFNDEF BOGUSLIB_H
#DEFINE BOGUSLIB_H

extern int callme(double* data);    

#ENDIF

我现在可以通过将Rust crate编译为cdylib,从Go中调用此函数:

//#cgo CFLAGS: -Ipath/to/libfolder
//#cgo LDFLAGS: -Lpath/to/libfolder -lboguslib
//#include <boguslib.h>
import "C"
import (
   "unsafe"
   . "fmt"  
)

func CallmeExternal() {
   data := make([]float64, 1, 1)
   data[0] = 1.0
   ptr := (*C.double)(unsafe.Pointer(&data[0]))
   size := C.callme(ptr)

   printf("size %v",size)
}

Go代码使用unsafe指针技巧来访问后备数组,因为切片的定义如下:
type Slice struct {
   data *byte
   uint32 len
   uint32 cap
}

当我执行以上代码时,传递的引用长度非常大。我该如何访问实际数据,此时返回的是什么?

5
在 FFI 接口中,你真的想使用目标语言理解的类型。在这里 &mut [...] 不是这样的类型。你是否查看了 FFI Omnibus - Matthieu M.
太好了!谢谢你提供的链接。 - user8725011
1个回答

8
根据The Rust FFI Omnibus提供的信息(由@matthieu-m提供),我已成功重写了代码。函数签名必须接受目标语言可以理解的类型。
Rust函数签名已更改为:
#[no_mangle]
pub extern "C" fn callme(slice: *const libc::c_double, len: libc::size_t) -> libc::c_int {
    let data = slice::from_raw_parts(slice, len as usize);
    data.len() as i32
}

头文件中的声明如下:
// skip include guards
#include <stdio.h>

extern int callme(double* slice, size_t len);

现在Go的调用也发生了变化

func CallmeExternal() {
   data := make([]float64, 2, 2)
   data[0] = 1.0
   ptr := (*C.double)(unsafe.Pointer(&data[0]))
   len := C.size_t(len(data))
   size := C.callme(ptr, len)

   printf("size %v",size)
}

这将返回2


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接