使用ctypes在Python中使用Rust返回的数组
问题内容:
我有一个Rust函数,返回一个array
,我想在中使用此数组Python
,可能是,list
或者numpy.array
这并不重要。
我的Rust函数如下所示:
#[no_mangle]
pub extern fn make_array() -> [i32; 4] {
let my_array: [i32; 4] = [1,2,3,4];
return my_array;
}
我试图像这样在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]
我究竟做错了什么?为什么我的输出没有[1,2,3,4]
?为什么我的前两个元素正确,而其他两个元素都填充有垃圾?
我在上找不到任何好的文档ctypes.ARRAY
,因此我只看了正确的内容,所以很可能是问题所在。
问题答案:
正如其他人所说,您不能 真正 正确地返回固定大小的数组。但是您可以通过将数组包装在结构中来 欺骗 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[:])
结果在[1, 2, 3, 4]
我的机器上。
附录 :这是一个“技巧”,因为我们正在利用C可以做什么和Rust可以做什么之间的差异。C 不允许 您按值返回固定大小的数组,但是Rust 会
,并且它的工作原理与返回用户定义的结构相同。
所以,我们做的东西是c 将 允许:返回恰好包含一个固定大小的数组结构。这很好,并且与Rust使用的布局匹配。
当然,这也有些怪异,因为我并不 完全 相信这是明确定义的行为。如果您想更加安全,可以在Rust一侧更改返回类型以匹配C:
#[repr(C)]
struct Int32_4 {
array: [i32; 4]
}