将字符串列表从Python传递给Rust

Waf*_*nut 12 python ctypes ffi rust

我现在已经学习Rust大约两个星期了,今天我进入了它的FFI.我使用Python来使用Rust,使用ctypes和libc.我通过整数,字符串甚至学会传递整数列表(感谢这个精彩的答案).

然后,我尝试传递一个字符串列表(按照该答案背后的推理),但我失败了,因为我无法获得领先.在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))
Run Code Online (Sandbox Code Playgroud)

在Rust中,我认为应该有一些东西(比如a 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);
}
Run Code Online (Sandbox Code Playgroud)

有没有其他方法来实现这一目标?

Vla*_*eev 12

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

蟒蛇:

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()
Run Code Online (Sandbox Code Playgroud)

锈:

#![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);
}
Run Code Online (Sandbox Code Playgroud)

运行:

% rustc --crate-type=dylib test.rs
% python test.py
["blah", "blah", "blah", "blah"]
Run Code Online (Sandbox Code Playgroud)

同样,你应该小心一生,并确保Vec<&str>不会超过Python方面的原始值.

  • 请注意,`feature(libc)`可以通过使用crates.io中的libc crate消失 (2认同)