使用ctypes在Python中使用Rust返回的数组

Aka*_*all 9 python ctypes rust

我有一个Rust函数返回一个array我想要使​​用这个数组Python,它可能是一个listnumpy.array它并不重要.

我的Rust功能如下所示:

#[no_mangle]
pub extern fn make_array() -> [i32; 4] {
    let my_array: [i32; 4] = [1,2,3,4];
    return my_array;
}
Run Code Online (Sandbox Code Playgroud)

我试图用Python调用它:

In [20]: import ctypes

In [21]: from ctypes import cdll

In [22]: lib = cdll.LoadLibrary("/home/user/RustStuff/embed/target/release/libembed.so")

In [23]: lib.make_array.restype = ctypes.ARRAY(ctypes.c_int32, 4)

In [24]: temp = lib.make_array()

In [25]: [i for i in temp]
Out[25]: [1, 2, -760202930, 32611]
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?为什么我的输出不是[1,2,3,4]?为什么我的前两个元素是正确的,另外两个元素是垃圾?

我无法找到任何好的文档ctypes.ARRAY,所以我只是选择了正确的,所以这可能是问题所在.

DK.*_*DK. 5

正如其他人所说,你无法真正正确地返回一个固定大小的数组.但是你可以通过将数组包装在一个结构中来欺骗 ctypes做正确的事情:

import ctypes

class Int32_4(ctypes.Structure):
    _fields_ = [("array", ctypes.c_int32 * 4)]

lib = ctypes.CDLL("embed.dll")
lib.make_array.restype = Int32_4

temp = lib.make_array()

print(temp.array[:])
Run Code Online (Sandbox Code Playgroud)

这导致[1, 2, 3, 4]我的机器.

附录:这是一个"技巧",因为我们正在利用C可以做什么和Rust可以做什么之间的差异.C 不会让你按值返回一个固定大小的数组,但Rust 会这样,它的工作方式与返回用户定义的结构相同.

所以,我们做的东西是c 允许:返回恰好包含一个固定大小的数组结构.这个很好,它与Rust正在使用的布局相匹配.

当然,这也有些愚蠢,因为我并不完全相信这是明确定义的行为.如果您想要更安全,可以更改Rust端的返回类型以匹配C:

#[repr(C)]
struct Int32_4 {
    array: [i32; 4]
}
Run Code Online (Sandbox Code Playgroud)