我想调用一些用Rust编写的外部函数来引用一个切片.
我有以下Rust代码:
extern crate libc;
#[no_mangle]
pub extern "C" fn callme(data: &mut [libc::c_double]) -> i32 {
data.len() as i32
}
Run Code Online (Sandbox Code Playgroud)
此函数通过此C风格的头文件可用于cgo编译器:
#IFNDEF BOGUSLIB_H
#DEFINE BOGUSLIB_H
extern int callme(double* data);
#ENDIF
Run Code Online (Sandbox Code Playgroud)
我现在可以使用编译为cdylib的Rust crate从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)
}
Run Code Online (Sandbox Code Playgroud)
Go代码使用不安全指针技巧来访问后备阵列,因为切片定义如下
type Slice struct {
data *byte
uint32 len
uint32 cap
}
Run Code Online (Sandbox Code Playgroud)
当我执行上面的代码时,传递的引用的长度非常大.如何访问实际数据,以及此时返回的内容是什么?
根据锈病FFI总括如由@马修-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
}
Run Code Online (Sandbox Code Playgroud)
头文件中的声明如下:
// skip include guards
#include <stdio.h>
extern int callme(double* slice, size_t len);
Run Code Online (Sandbox Code Playgroud)
来自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)
}
Run Code Online (Sandbox Code Playgroud)
这回来了2.