将字符串列表从Python传递到Rust [英] Passing a list of strings from Python to Rust

查看:176
本文介绍了将字符串列表从Python传递到Rust的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经学习Rust大约两周了,而今天,我进入了FFI。我使用Python使用ctypes和libc来玩Rust。我传递了整数,字符串,甚至学会了传递整数列表(感谢这个奇妙的答案)。

I've been learning Rust for about two weeks now and today, I got into its FFI. I used Python to play with Rust, using ctypes and libc. I passed integers, strings and even learned to pass a list of integers (thanks to this wonderful answer).

然后,我尝试传递一个字符串列表(遵循该答案的原因),但由于未能获得领先,所以我失败了。在Python中,我有类似这样的方法来传递字符串数组。

Then, I tried to pass a list of strings (following the reasoning behind the that answer), but I failed, as I couldn't get a lead on it. In Python, I have something like this to pass the array of strings.

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 )来收集传入的字符串,但我找不到一个。

In Rust, I thought that there should be something (like a STRING_RECEIVER) to collect the incoming strings, but I can't find one.

#![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);
}

是否有其他方法可以实现这一目标?

Is there any alternative way to achieve this?

推荐答案

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

There is absolutely no difference with the case of array of numbers. C strings are zero-terminated arrays of bytes, so their representation in Rust will be *const c_char, which could then be converted to &CStr which then can be used to obtain &[u8] and then &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()

Rust:

#![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<& str> 在Python方面没有超过原始值。

And again, you should be careful with lifetimes and ensure that Vec<&str> does not outlive the original value on the Python side.

这篇关于将字符串列表从Python传递到Rust的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆