关键词:
【中文标题】将元组的 Rust 向量转换为 C 兼容结构【英文标题】:Convert Rust vector of tuples to a C compatible structure 【发布时间】:2015-09-08 04:25:17 【问题描述】:按照theseanswers,我目前定义了一个Rust 1.0函数如下,以便可以使用ctypes
从Python调用:
use std::vec;
extern crate libc;
use libc::c_int, c_float, size_t;
use std::slice;
#[no_mangle]
pub extern fn convert_vec(input_lon: *const c_float,
lon_size: size_t,
input_lat: *const c_float,
lat_size: size_t) -> Vec<(i32, i32)>
let input_lon = unsafe
slice::from_raw_parts(input_lon, lon_size as usize)
;
let input_lat = unsafe
slice::from_raw_parts(input_lat, lat_size as usize)
;
let combined: Vec<(i32, i32)> = input_lon
.iter()
.zip(input_lat.iter())
.map(|each| convert(*each.0, *each.1))
.collect();
return combined
我正在像这样设置 Python 部分:
from ctypes import *
class Int32_2(Structure):
_fields_ = [("array", c_int32 * 2)]
rust_bng_vec = lib.convert_vec_py
rust_bng_vec.argtypes = [POINTER(c_float), c_size_t,
POINTER(c_float), c_size_t]
rust_bng_vec.restype = POINTER(Int32_2)
这似乎没问题,但我是:
不确定如何将combined
(Vec<(i32, i32)>
)转换为与 C 兼容的结构,以便可以将其返回到我的 Python 脚本中。
不确定我是否应该返回一个引用 (return &combined
?),如果我这样做了,我将如何使用适当的生命周期说明符来注释函数
【问题讨论】:
不要在您的问题中提出解决方案。如果您想分享对您有用的代码,您可以发布自己的答案。 【参考方案1】:最需要注意的是,C 中没有元组这样的东西。C 是库互操作性的通用语言,你会被要求限制自己使用这种语言的能力。如果你在 Rust 和另一种高级语言之间交谈,这并不重要;你必须说C。
C 中可能没有元组,但有struct
s。一个二元素元组只是一个有两个成员的结构!
让我们从我们要编写的 C 代码开始:
#include <stdio.h>
#include <stdint.h>
typedef struct
uint32_t a;
uint32_t b;
tuple_t;
typedef struct
void *data;
size_t len;
array_t;
extern array_t convert_vec(array_t lat, array_t lon);
int main()
uint32_t lats[3] = 0, 1, 2;
uint32_t lons[3] = 9, 8, 7;
array_t lat = .data = lats, .len = 3 ;
array_t lon = .data = lons, .len = 3 ;
array_t fixed = convert_vec(lat, lon);
tuple_t *real = fixed.data;
for (int i = 0; i < fixed.len; i++)
printf("%d, %d\n", real[i].a, real[i].b);
return 0;
我们定义了两个struct
s——一个代表我们的元组,另一个代表一个数组,因为我们将来回传递它们。
我们将通过在 Rust 中定义 完全相同 结构来跟进这一点,并将它们定义为具有 完全相同 成员(类型、排序、名称)。重要的是,我们使用 #[repr(C)]
让 Rust 编译器知道不要对数据进行重新排序。
extern crate libc;
use std::slice;
use std::mem;
#[repr(C)]
pub struct Tuple
a: libc::uint32_t,
b: libc::uint32_t,
#[repr(C)]
pub struct Array
data: *const libc::c_void,
len: libc::size_t,
impl Array
unsafe fn as_u32_slice(&self) -> &[u32]
assert!(!self.data.is_null());
slice::from_raw_parts(self.data as *const u32, self.len as usize)
fn from_vec<T>(mut vec: Vec<T>) -> Array
// Important to make length and capacity match
// A better solution is to track both length and capacity
vec.shrink_to_fit();
let array = Array data: vec.as_ptr() as *const libc::c_void, len: vec.len() as libc::size_t ;
// Whee! Leak the memory, and now the raw pointer (and
// eventually C) is the owner.
mem::forget(vec);
array
#[no_mangle]
pub extern fn convert_vec(lon: Array, lat: Array) -> Array
let lon = unsafe lon.as_u32_slice() ;
let lat = unsafe lat.as_u32_slice() ;
let vec =
lat.iter().zip(lon.iter())
.map(|(&lat, &lon)| Tuple a: lat, b: lon )
.collect();
Array::from_vec(vec)
我们必须绝不在 FFI 边界上接受或返回非repr(C)
类型,因此我们通过Array
。请注意,有大量的unsafe
代码,因为我们必须将指向数据的未知指针 (c_void
) 转换为特定类型。这就是 C 世界中泛型的代价。
现在让我们把目光转向 Python。基本上,我们只需要模仿 C 代码所做的:
import ctypes
class FFITuple(ctypes.Structure):
_fields_ = [("a", ctypes.c_uint32),
("b", ctypes.c_uint32)]
class FFIArray(ctypes.Structure):
_fields_ = [("data", ctypes.c_void_p),
("len", ctypes.c_size_t)]
# Allow implicit conversions from a sequence of 32-bit unsigned
# integers.
@classmethod
def from_param(cls, seq):
return cls(seq)
# Wrap sequence of values. You can specify another type besides a
# 32-bit unsigned integer.
def __init__(self, seq, data_type = ctypes.c_uint32):
array_type = data_type * len(seq)
raw_seq = array_type(*seq)
self.data = ctypes.cast(raw_seq, ctypes.c_void_p)
self.len = len(seq)
# A conversion function that cleans up the result value to make it
# nicer to consume.
def void_array_to_tuple_list(array, _func, _args):
tuple_array = ctypes.cast(array.data, ctypes.POINTER(FFITuple))
return [tuple_array[i] for i in range(0, array.len)]
lib = ctypes.cdll.LoadLibrary("./target/debug/libtupleffi.dylib")
lib.convert_vec.argtypes = (FFIArray, FFIArray)
lib.convert_vec.restype = FFIArray
lib.convert_vec.errcheck = void_array_to_tuple_list
for tupl in lib.convert_vec([1,2,3], [9,8,7]):
print tupl.a, tupl.b
原谅我的初级 Python。 我相信有经验的 Pythonista 可以让这个看起来更漂亮!感谢@eryksun 提供了some nice advice 如何让调用方法的消费者方面更好更多 .
关于所有权和内存泄漏的一句话
在这个示例代码中,我们泄露了Vec
分配的内存。理论上,FFI 代码现在拥有内存,但实际上,它不能用它做任何有用的事情。要获得一个完全正确的示例,您需要添加另一个方法来接受从被调用者返回的指针,将其转换回 Vec
,然后允许 Rust 删除该值。这是唯一安全的方法,因为 Rust 几乎可以保证使用与您的 FFI 语言使用的内存分配器不同的内存分配器。
不确定我是否应该返回一个引用,以及如果我这样做了,我将如何使用适当的生命周期说明符来注释函数
不,您不想(阅读:不能)返回引用。如果可以,那么项目的所有权将以函数调用结束,并且引用将指向任何内容。这就是为什么我们需要使用mem::forget
进行两步舞并返回一个原始指针。
【讨论】:
这非常彻底。非常感谢。 这里是from_param
和errcheck
的文档链接。
@eryksun 您有没有机会整理一个包含您的建议的基本示例?
@eryksun 我已经更新了,再次感谢!我最不确定的部分是errcheck
函数;我写的方式有意义吗?
我会使用 return ctypes.cast(array.data, ctypes.POINTER(FFITuple * array.len))[0]
返回一个 FFITuple
数组。另外,我忘了在from_param
中你应该传递一个类的实例,例如return arg if isinstance(arg, cls) else cls(arg)
.如何使用列表推导将元组的元组转换为一维列表? [复制]
】如何使用列表推导将元组的元组转换为一维列表?[复制]【英文标题】:HowdoIconvertatupleoftuplestoaone-dimensionallistusinglistcomprehension?[duplicate]【发布时间】:2011-03-1308:47:37【问题描述】:我有一个元组-例如:tupleOfTuples=((1,2),(3,4),(5,)... 查看详情
Typescript 将元组的类型元组转换为元组(扁平元组)
】Typescript将元组的类型元组转换为元组(扁平元组)【英文标题】:TypescriptconverttypeTupleoftupletoTuple(flattenTuple)【发布时间】:2020-04-1101:01:12【问题描述】:我有这个TypeT=Params<[Tuple1,Tuple2]>//eg[[string],[number]]如何制作(展平)T... 查看详情
将元组的字符串表示形式转换为真正的元组
】将元组的字符串表示形式转换为真正的元组【英文标题】:Convertastringrepresentationofatupletoarealtuple【发布时间】:2015-12-1922:11:26【问题描述】:如何将这个字符串"[type,a,to,room01023123,body,heywhat\'supmister,by,someone]"转换成这样... 查看详情
将元组的无序列表转换为 pandas DataFrame
】将元组的无序列表转换为pandasDataFrame【英文标题】:ConvertingunorderedlistoftuplestopandasDataFrame【发布时间】:2018-05-2920:57:57【问题描述】:我正在使用库usaddress从我拥有的一组文件中解析地址。我希望我的最终输出是一个数据框,... 查看详情
如何将元组列表转换为 pandas 数据框,以便每个元组的第一个值代表一列?
】如何将元组列表转换为pandas数据框,以便每个元组的第一个值代表一列?【英文标题】:HowcanItransformalistoftuplesintoapandasdataframesothatthefirstvalueofeachtuplerepresentsacolumn?【发布时间】:2020-04-1315:47:33【问题描述】:我想转换我的元... 查看详情
Spark 2.0:如何将元组的 RDD 转换为 DF [重复]
】Spark2.0:如何将元组的RDD转换为DF[重复]【英文标题】:Spark2.0:howtoconvertaRDDofTuplestoDF[duplicate]【发布时间】:2017-06-0103:12:16【问题描述】:我正在将我的一个项目从Spark1.6升级到Spark2.0.1。以下代码适用于Spark1.6,但不适用于2.0.1... 查看详情
如何创建将二叉树转换为元组的函数?
...2-0100:56:43【问题描述】:我遇到了这个问题,我的任务是将元组转换为二叉树,然后将二叉树转换回元组并返回树和元组。我能够将元组转换为树,但我未能创建一个函数来执行相反的操作。我只是一个尝试学习数据结构的初学... 查看详情
如何在python中将元组列表转换为元组的元组[重复]
】如何在python中将元组列表转换为元组的元组[重复]【英文标题】:Howtoconvertlistoftuplestotupleoftuplesinpython[duplicate]【发布时间】:2017-07-3001:50:40【问题描述】:我正在尝试将元组列表转换为元组元组,我做错了,请帮助解决此问题... 查看详情
如何在 Python 中将元组的元组转换为 pandas.DataFrame?
】如何在Python中将元组的元组转换为pandas.DataFrame?【英文标题】:Howtoconverttupleoftuplestopandas.DataFrameinPython?【发布时间】:2016-02-1512:00:00【问题描述】:没有冒犯,如果问题太基本。如果您需要更多信息,请告诉我。我正在寻找... 查看详情
将元组列表转换为字典
】将元组列表转换为字典【英文标题】:Convertingalistoftuplesintoadict【发布时间】:2010-09-2016:07:28【问题描述】:我有一个这样的元组列表:[(\'a\',1),(\'a\',2),(\'a\',3),(\'b\',1),(\'b\',2),(\'c\',1),]我想通过第一项来遍历这个键控,因此,... 查看详情
将元组的元素插入数据库
】将元组的元素插入数据库【英文标题】:Insertingtuple\'selementstodatabase【发布时间】:2011-12-2411:39:07【问题描述】:我有一个元组,我想存储它的元素,我试图将它插入如下,它给出了以下错误,我做错了什么?records_to_be_inserted... 查看详情
如何将元组类型转换为联合?
】如何将元组类型转换为联合?【英文标题】:Howtoconvertatupletypetoaunion?【发布时间】:2020-04-0200:15:31【问题描述】:如何将元组泛型类型映射到联合类型?typeNeededUnionType<T>=T[keyofT];//IncludesalltheArraypropertiesvaluesconstvalue:NeededUn... 查看详情
将元组列表转换为 Pandas 系列
】将元组列表转换为Pandas系列【英文标题】:ConvertingalistoftuplestoaPandasseries【发布时间】:2019-04-2104:00:17【问题描述】:我有一个要转换为系列的元组列表。returnarray2[(0,0.07142857142857142),(0,0.07142857142857142),(1,0.08333333333333333),(1,0.3333... 查看详情
TypeScript:将元组类型转换为对象
】TypeScript:将元组类型转换为对象【英文标题】:TypeScript:converttupletypetoobject【发布时间】:2021-11-0404:34:13【问题描述】:总结:我有一个这样的元组类型:[session:SessionAgent,streamID:string,isScreenShare:boolean,connectionID:string,videoProducer... 查看详情
如何将元组中的字典列表转换为表格数据/熊猫数据框?
】如何将元组中的字典列表转换为表格数据/熊猫数据框?【英文标题】:Howtoconvertalistofdictionariesinsideatupleintotabulardata/pandasDataFrame?【发布时间】:2017-07-1121:02:06【问题描述】:我目前有一个包含两个元素的元组列表,一个字符... 查看详情
Python将元组转换为值
】Python将元组转换为值【英文标题】:Pythontoconverttupletovalue【发布时间】:2018-05-3114:29:47【问题描述】:我正在尝试检索表中的行数与:importpostgresqldb=postgresql.open(...)res=db.query("selectcount(1)fromtestdata")print(res)>>>(10,)如何只打... 查看详情
将元组中的列表转换为numpy数组?
】将元组中的列表转换为numpy数组?【英文标题】:Convertlistintupletonumpyarray?【发布时间】:2011-01-2501:05:40【问题描述】:我有列表元组。这些列表之一是分数列表。我想将分数列表转换为numpy数组,以利用scipy提供的预构建统计... 查看详情
Python:将元组转换为二维数组
】Python:将元组转换为二维数组【英文标题】:Python:convertingtupleinto2Darray【发布时间】:2016-04-2219:44:07【问题描述】:我想像这样转换元组t=[(4,10),(9,7),(11,2),(2,2)]像这样的二维数组:a=[[4,10],[9,7],[11,2],[2,2]]我试过了a=[]foriint:a.append... 查看详情