python - 从 Rust 函数返回字符串到 Python

标签 python rust

我对 Rust 很陌生。如何从可在 Python 中使用的 Rust 函数返回 String

这是我的 Rust 实现:

use std::ffi::CString;

#[no_mangle]
pub extern fn query() -> CString {
    let s = CString::new("Hello!").unwrap();
    return s;
}

以及调用它的 Python 代码:

from ctypes import cdll, c_char_p

lib = cdll.LoadLibrary("target/release/libtest.so")
result = lib.query()

print(c_char_p(result).value)

运行时出现段错误。

编辑:使用下面的 Vladimir Matveev 的 Rust 代码,我能够让它与我的 python 代码的更改一起工作:

from ctypes import *

lib = cdll.LoadLibrary("target/release/libtest.so")
lib.query.restype = c_char_p
result = lib.query()
print cast(result, c_char_p).value
lib.free_query(result)

最佳答案

最直接的版本是这样的:

use libc::c_char;
use std::ffi::CString;
use std::mem;

#[no_mangle]
pub extern fn query() -> *mut c_char {
    let s = CString::new("Hello!").unwrap();
    s.into_raw()
}

这里我们返回一个指向char的零终止序列的指针s 可以传递给 Python 的 c_char_p .你不能只返回 CString因为它是 Rust 结构,不应该直接在 C 代码中使用 - 它包装了 Vec<u8>实际上由三个指针大小的整数组成。它与 C 的 char* 不兼容直接地。我们需要从中获取一个原始指针。 CString::into_raw() 方法这样做 - 它消耗 CString按值,“忘记”它,因此它的分配不会被破坏,并返回 *mut c_char指向数组开头的指针。

但是,这样字符串会被泄露,因为我们忘记了它在 Rust 端的分配,而且它永远不会被释放。我不太了解 Python 的 FFI,但解决这个问题的最直接方法是创建两个函数,一个用于生成数据,一个用于释放数据。然后你需要通过调用这个释放函数从 Python 端释放数据:

// above function
#[no_mangle]
pub extern fn query() -> *mut c_char { ... }

#[no_mangle]
pub extern fn free_query(c: *mut c_char) {
    // convert the pointer back to `CString`
    // it will be automatically dropped immediately
    unsafe { CString::from_raw(c); }
}

CString::from_raw() 方法接受 *mut c_char指针并创建一个 CString从中取出实例,计算进程中底层以零结尾的字符串的长度。此操作意味着所有权转移,因此得到 CString value 将拥有分配,当它被删除时,分配被释放。这正是我们想要的。

关于python - 从 Rust 函数返回字符串到 Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30510764/

相关文章:

python - 在 macOS Lion 上构建 pytable

python - 为什么 Django cms 站点地图 url 在所有浏览器中都不匹配?

rust - 特征绑定(bind) T : From<Result<T, 错误>>不满足

plugins - 如何配置 cargo 将项目构建到特定目录?

python - cross_validation模块是否从sklearn中删除了?如果是,从哪个版本开始?

python - 函数认为我正在传递一个 float

Python 传输机械化浏览器 session

rust - 如何将格式化字符串写入文件?

error-handling - 有没有办法在任意 `.backtrace()` 特征对象上获取 SNAFU 的 `&dyn std::error::Error`?

rust - 如何高效地将可显示项插入字符串?