【问题标题】:How can I call a Rust function from Go with a slice as a parameter?如何使用切片作为参数从 Go 调用 Rust 函数?
【发布时间】:2018-04-14 22:54:55
【问题描述】:

我想从 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

我现在可以使用编译为 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)
}

Go 代码使用不安全指针技巧来访问支持数组,因为切片定义如下

type Slice struct {
   data *byte
   uint32 len
   uint32 cap
}

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

【问题讨论】:

  • 在 FFI 接口中,您确实希望坚持使用目标语言可以理解的类型。在这里,&amp;mut [...] 不是。你检查过FFI Omnibus吗?
  • 太棒了!谢谢你的链接。

标签: go rust ffi


【解决方案1】:

根据The Rust FFI Omnibus作为provided by @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

【讨论】:

    猜你喜欢
    • 2021-04-23
    • 1970-01-01
    • 2016-03-26
    • 1970-01-01
    • 2022-01-01
    • 2021-01-22
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多