如果你真的想返回数组的话 , 那么可以将数组拼接成字符串 , 然后返回 。
use std::ffi::{c_char, CString};#[no_mangle]pub extern "C" fn create_array() -> *mut c_char { // 筛选出 1 到 50 中,能被 3 整除的数 // 并以逗号为分隔符 , 将这些整数拼接成字符串 let vec = (1..=50) .filter(|c| *c % 3 == 0) .map(|c| c.to_string()) .collect::<Vec<String>>() .join(","); CString::new(vec).unwrap().into_raw()}编译之后交给 Python 调用 。
from ctypes import *py_lib = CDLL("../py_lib/target/debug/libpy_lib.dylib")# 只要是需要释放的堆内存,都建议按照 c_void_p 来解析py_lib.create_array.restype = c_void_p# 此时拿到的就是指针保存的地址,在 Python 里面就是一串整数ptr = py_lib.create_array()# 由于是字符串首字符的地址,所以转成 char * , 拿到具体内容print(cast(ptr, c_char_p).value.decode("utf-8"))"""3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48"""# 此时我们就将数组拼接成字符串返回了# 但是堆区的 CString 还在,所以还要释放掉,调用 free 函数即可# 注意:ptr 只是一串整数,或者说它就是 Python 的一个 int 对象# 换句话说 ptr 只是保存了地址值,但它不具备指针的含义# 因此需要再使用 c_void_p 包装一下(转成指针),才能传给 free 函数py_lib.free(c_void_p(ptr))因此虽然不建议返回数组,但将数组转成字符串返回也不失为一个办法,当然除了数组,你还可以将更复杂的结构转成字符串返回 。
传递结构体结构体应该是 Rust 里面最重要的结构之一了,它要如何和外部交互呢?
use std::ffi::c_char;#[repr(C)]pub struct Girl { pub name: *mut c_char, pub age: u8,}#[no_mangle]pub extern "C" fn create_struct(name: *mut c_char, age: u8) -> Girl { Girl { name, age }}因为结构体实例要返回给外部 , 所以它的字段类型必须是兼容的,不能定义 C 理解不了的类型 。然后还要设置 #[repr(C)] 属性,来保证结构体的内存布局和 C 是兼容的 。
下面通过 cargo build 命令编译成动态库,Python 负责调用 。
from ctypes import *py_lib = CDLL("../py_lib/target/debug/libpy_lib.dylib")class Girl(Structure): _fields_ = [ ("name", c_char_p), ("age", c_uint8), ]# 指定 create_struct 的返回值类型为 Girlpy_lib.create_struct.restype = Girlgirl = py_lib.create_struct( c_char_p("S 老师".encode("utf-8")), c_uint8(18))print(girl.name.decode("utf-8")) # S 老师print(girl.age) # 18调用成功,并且此时是没有内存泄露的 。
当通过 FFI 将数据从 Rust 传递到 Python 时,如果传递的是指针,那么会涉及内存释放的问题 。但如果传递的是值,那么它会复制一份给 Python,而原始的值(这里是结构体实例)会被自动销毁,所以无需担心 。
然后是结构体内部的字段 , 虽然里面的 name 字段是 *mut c_char,但它的值是由 Python 传过来的,而不是在 Rust 内部创建的 , 因此没有问题 。
但如果将 Rust 代码改一下:
use std::ffi::{c_char, CString};#[repr(C)]pub struct Girl { pub name: *mut c_char, pub age: u8,}#[no_mangle]pub extern "C" fn create_struct() -> Girl { let name = CString::new("S 老师").unwrap().into_raw(); let age = 18; Girl { name, age }}
推荐阅读
- 你知道 Python 其实自带了小型数据库吗
- 解密Java连接MySQL的最佳实践:选择适合你的方式
- QQ如何用指纹解锁
- 怎么成为淘宝买菜的团长 如何申请成为淘宝买菜团长
- 如何制作三角形笔刷ps,ps该如何才可以画出三角形
- 在拼多多上如何修改评价,拼多多怎么修改评价等级
- cdr中应该如何画波浪线
- cdr2020如何合并打印,cdr该如何才可以进行打印
- 水泥路面起砂如何处理 水泥路面起砂如何处理视频
- 装修公司如何选 装修公司如何选好门店
