Usando Rust devolvió la matriz en Python usando ctypes

Tengo una función Rust que devuelve una array y quiero usar esta matriz en Python , podría ser una list o numpy.array que realmente no importa.

Mi función de rust se parece a esto:

 #[no_mangle] pub extern fn make_array() -> [i32; 4] { let my_array: [i32; 4] = [1,2,3,4]; return my_array; } 

Y estoy tratando de llamarlo en Python así:

 In [20]: import ctypes In [21]: from ctypes import cdll In [22]: lib = cdll.LoadLibrary("/home/user/RustStuff/embed/target/release/libembed.so") In [23]: lib.make_array.restype = ctypes.ARRAY(ctypes.c_int32, 4) In [24]: temp = lib.make_array() In [25]: [i for i in temp] Out[25]: [1, 2, -760202930, 32611] 

¿Qué estoy haciendo mal? ¿Por qué mi salida no es [1,2,3,4] ? ¿Por qué mis dos primeros elementos son correctos y los otros dos están poblados con basura?

No pude encontrar ninguna buena documentación en ctypes.ARRAY , así que simplemente busqué lo que parecía correcto, por lo que ese es probablemente el problema.

Como han dicho otros, realmente no puede devolver una matriz de tamaño fijo correctamente. Pero puedes engañar a los ctypes para que hagan lo correcto envolviendo la matriz en una estructura:

 import ctypes class Int32_4(ctypes.Structure): _fields_ = [("array", ctypes.c_int32 * 4)] lib = ctypes.CDLL("embed.dll") lib.make_array.restype = Int32_4 temp = lib.make_array() print(temp.array[:]) 

Esto da como resultado [1, 2, 3, 4] en mi máquina.

Anexo : Este es un “truco” porque estamos explotando una diferencia entre lo que C puede hacer y lo que Rust puede hacer. C no le permitirá devolver una matriz de tamaño fijo por valor, pero Rust lo hará , y funciona igual que devolver una estructura definida por el usuario.

Entonces, hacemos algo que C permitirá: devolver una estructura que contenga una matriz de tamaño fijo. Con esto está bien y coincide con el diseño que utiliza Rust.

Por supuesto, esto también es algo intrincado, ya que no estoy completamente convencido de que este sea un comportamiento bien definido. Si desea ser más seguro, puede cambiar el tipo de retorno en el lado de rust para que coincida con C:

 #[repr(C)] struct Int32_4 { array: [i32; 4] } 

Estoy de acuerdo con lo que dijo @delnan : no se pueden devolver matrices de tamaño fijo en C. Una de las principales incompatibilidades es que las matrices Rust saben de qué tamaño son, pero las matrices C no. Deberá respetar cómo lo ha hecho cada progtwig de C: devuelva un puntero y una longitud por separado. ¿No es Rust un buen lenguaje moderno en comparación?

Robé y modifiqué un código Python de otra respuesta.

 import ctypes from ctypes import cdll lib = cdll.LoadLibrary("libarray.dylib") lib.make_array.restype = ctypes.POINTER(ctypes.c_int32 * 4) print [i for i in lib.make_array().contents] 

Esto funciona con este código Rust:

 static ARRAY: [i32; 4] = [1,2,3,4]; #[no_mangle] pub extern fn make_array() -> *const i32 { ARRAY.as_ptr() } 

Aquí, estamos haciendo lo más simple, creando una matriz que vivirá durante toda la duración del progtwig y devolviendo una referencia a sus datos. En su progtwig real, es probable que deba tener más cuidado para asegurarse de que su Vec o &[i32] sobreviva estrictamente durante cuánto tiempo el código Python tiene el puntero, de lo contrario, causará daños en la memoria.