然后 Python 进行调用:
from ctypes import *py_lib = CDLL("../py_lib/target/debug/libpy_lib.dylib")a, b = c_int(22), c_int(33)# 指定类型为 c_void_ppy_lib.add.restype = c_void_p# 拿到指针保存的地址ptr = py_lib.add(pointer(a), pointer(b))# 将 c_void_p 转成 POINTER(c_int) 类型 , 也就是 c_int *# 通过它的 contents 属性拿到具体的值print(cast(ptr, POINTER(c_int)).contents) # c_int(55)print(cast(ptr, POINTER(c_int)).contents.value) # 55# 释放堆内存py_lib.free_i32(c_void_p(ptr))这样我们就拿到了指针,并且也不会出现内存泄露 。但是单独定义一个释放函数还是有些麻烦的 , 所以 Rust 自动提供了一个 free 函数,专门用于释放堆内存 。举个例子:
use std::ffi::{CStr, CString};use std::os::raw::c_char;#[no_mangle]pub extern "C" fn to_uppercase(s: *const c_char) -> *mut c_char { let s = unsafe { CStr::from_ptr(s) }; let s = s.to_str().unwrap().to_uppercase(); CString::new(s).unwrap().into_raw()}#[no_mangle]pub extern "C" fn add(a: *const i32, b: *const i32) -> *mut i32 { let res = unsafe {*a + *b}; Box::into_raw(Box::new(res))}这是出现过的两个函数,它们的内存都申请在堆区,但我们将内存释放函数删掉了,因为 Rust 自动提供了一个 free 函数 , 专门用于堆内存的释放 。
from ctypes import *py_lib = CDLL("../py_lib/target/debug/libpy_lib.dylib")# 返回值类型指定为 c_void_p,表示万能指针py_lib.to_uppercase.restype = c_void_ppy_lib.add.restype = c_void_pptr1 = py_lib.to_uppercase( c_char_p("Serpen 老师".encode("utf-8")))ptr2 = py_lib.add( pointer(c_int(123)), pointer(c_int(456)))# 函数调用完毕,将地址转成具体的类型的指针print(cast(ptr1, c_char_p).value.decode("utf-8"))"""SERPEN 老师"""print(cast(ptr2, POINTER(c_int)).contents.value)"""579"""# 释放堆内存,直接调用 free 函数即可,非常方便py_lib.free(c_void_p(ptr1))py_lib.free(c_void_p(ptr2))以上我们就实现了指针的传递和返回,但对于整数、浮点数而言 , 直接返回它们的值即可,没必要返回指针 。
传递数组下面来看看如何传递数组,由于数组在作为参数传递的时候会退化为指针,所以数组的长度信息就丢失了,使用 sizeof 计算出来的结果就是一个指针的大小 。因此将数组作为参数传递的时候,应该将当前数组的长度信息也传递过去,否则可能会访问非法的内存 。
我们实现一个功能,Rust 接收一个 Python 数组,进行原地排序 。
use std::slice;#[no_mangle]pub extern "C" fn sort_array(arr: *mut i32, len: usize) { assert!(!arr.is_null()); unsafe { // 得到一个切片 &mut[i32] let slice = slice::from_raw_parts_mut(arr, len); slice.sort(); // 排序 }}然后 Python 进行调用:
from ctypes import *py_lib = CDLL("../py_lib/target/debug/libpy_lib.dylib")# 一个列表data = [3, 2, 1, 5, 4, 7, 6]# 但是列表不能传递,必须要转成 C 数组# Array_Type 就相当于 C 的 int array[len(data)]Array_Type = c_int * len(data)# 创建数组array = Array_Type(*data)print(list(array)) # [3, 2, 1, 5, 4, 7, 6]py_lib.sort_array(array, len(array))print(list(array)) # [1, 2, 3, 4, 5, 6, 7]排序实现完成,这里的数组是 Python 传过去的,并且进行了原地修改 。那 Rust 可不可以返回数组给 Python 呢?从理论上来说可以,但实际不建议这么做,因为你不知道返回的数组的长度是多少?
推荐阅读
- 你知道 Python 其实自带了小型数据库吗
- 解密Java连接MySQL的最佳实践:选择适合你的方式
- QQ如何用指纹解锁
- 怎么成为淘宝买菜的团长 如何申请成为淘宝买菜团长
- 如何制作三角形笔刷ps,ps该如何才可以画出三角形
- 在拼多多上如何修改评价,拼多多怎么修改评价等级
- cdr中应该如何画波浪线
- cdr2020如何合并打印,cdr该如何才可以进行打印
- 水泥路面起砂如何处理 水泥路面起砂如何处理视频
- 装修公司如何选 装修公司如何选好门店
