【问题标题】:Passing a list of strings from Python to Rust将字符串列表从 Python 传递给 Rust
【发布时间】:2015-06-26 13:51:14
【问题描述】:

我已经学习 Rust 大约两个星期了,今天,我进入了它的 FFI。我使用 Python 来玩 Rust,使用 ctypes 和 libc。我传递了整数、字符串,甚至学会了传递整数列表 (thanks to this wonderful answer)。

然后,我尝试传递一个字符串列表(按照该答案背后的推理),但我失败了,因为我无法获得领先。在 Python 中,我有这样的东西来传递字符串数组。

def testRust():
    lib = ctypes.cdll.LoadLibrary(rustLib)
    list_to_send = ['blah', 'blah', 'blah', 'blah']
    c_array = (ctypes.c_char_p * len(list_to_send))()
    lib.get_strings(c_array, len(list_to_send))

在 Rust 中,我认为应该有一些东西(比如 STRING_RECEIVER)来收集传入的字符串,但我找不到。

#![feature(libc)]
extern crate libc;

use std::slice;
use libc::{size_t, STRING_RECEIVER};

#[no_mangle]
pub extern fn get_strings(array: *const STRING_RECEIVER, length: size_t) {
    let values = unsafe { slice::from_raw_parts(array, length as usize) };
    println!("{:?}", values);
}

有没有其他方法可以做到这一点?

【问题讨论】:

    标签: python rust ctypes ffi


    【解决方案1】:

    数字数组的情况绝对没有区别。 C 字符串是以零结尾的字节数组,因此它们在 Rust 中的表示形式为*const c_char,然后可以转换为&CStr,然后可以使用它来获取&[u8],然后是&str

    Python:

    import ctypes
    
    rustLib = "libtest.dylib"
    
    def testRust():
        lib = ctypes.cdll.LoadLibrary(rustLib)
        list_to_send = ['blah', 'blah', 'blah', 'blah']
        c_array = (ctypes.c_char_p * len(list_to_send))(*list_to_send)
        lib.get_strings(c_array, len(list_to_send))
    
    if __name__=="__main__":
        testRust()
    

    生锈:

    #![feature(libc)]
    extern crate libc;
    
    use std::slice;
    use std::ffi::CStr;
    use std::str;
    use libc::{size_t, c_char};
    
    #[no_mangle]
    pub extern fn get_strings(array: *const *const c_char, length: size_t) {
        let values = unsafe { slice::from_raw_parts(array, length as usize) };
        let strs: Vec<&str> = values.iter()
            .map(|&p| unsafe { CStr::from_ptr(p) })  // iterator of &CStr
            .map(|cs| cs.to_bytes())                 // iterator of &[u8]
            .map(|bs| str::from_utf8(bs).unwrap())   // iterator of &str
            .collect();
        println!("{:?}", strs);
    }
    

    跑步:

    % rustc --crate-type=dylib test.rs
    % python test.py
    ["blah", "blah", "blah", "blah"]
    

    同样,您应该注意生命周期,并确保 Vec&lt;&amp;str&gt; 在 Python 端不会超过原始值。

    【讨论】:

    • 这太棒了!我从来没有想过我们可以做类似*const *const c_char 的事情。感谢您的快速回答:)
    • 请注意,feature(libc) 可以通过使用 crates.io 的 libc crate 消失
    猜你喜欢
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多