Rust 函数:接受并返回元组
C 没有元组的概念,但最接近的模拟是一个普通的结构。 您需要为每种独特的类型组合,创建单独的结构。在这里,我们创建一个结构,它表示两个 32 位无符号整数。
extern crate libc;
use libc::uint32_t;
use std::convert::From;
// A Rust function that accepts a tuple
fn flip_things_around_rust(tup: (u32, u32)) -> (u32, u32) {
let (a, b) = tup;
(b+1, a-1)
}
// A struct that can be passed between C and Rust
#[repr(C)]
pub struct Tuple {
x: uint32_t,
y: uint32_t,
}
// Conversion functions
impl From<(u32, u32)> for Tuple {
fn from(tup: (u32, u32)) -> Tuple {
Tuple { x: tup.0, y: tup.1 }
}
}
impl From<Tuple> for (u32, u32) {
fn from(tup: Tuple) -> (u32, u32) {
(tup.x, tup.y)
}
}
// The exported C method
#[no_mangle]
pub extern fn flip_things_around(tup: Tuple) -> Tuple {
flip_things_around_rust(tup.into()).into()
}
#[allow(dead_code)]
pub extern fn fix_linking_when_not_using_stdlib() { panic!() }
#[repr(C)]
用于通知编译器,它应该像 C 编译器那样排列结构的字段。在结构和相应的元组之间的转换实现,都用到了std::convert::From
trait,提供符合人体工程学的转换操作。
C
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint32_t x;
uint32_t y;
} tuple_t;
extern tuple_t flip_things_around(tuple_t);
int main(void) {
tuple_t initial = { .x = 10, .y = 20 };
tuple_t new = flip_things_around(initial);
printf("(%u,%u)\n", new.x, new.y);
return 0;
}
由于我们符合 C 兼容的习语,因此实现是直截了当的。我们定义一个struct
,使用与 Rust 结构的类型和顺序匹配的字段,然后创建一个实例并调用该方法。
Ruby
require 'ffi'
class Tuple < FFI::Struct
layout :x, :uint32,
:y, :uint32
def to_s
"(#{self[:x]},#{self[:y]})"
end
end
module Tuples
extend FFI::Library
ffi_lib 'tuples'
attach_function :flip_things_around, [Tuple.by_value], Tuple.by_value
end
tup = Tuple.new
tup[:x] = 10
tup[:y] = 20
puts Tuples.flip_things_around(tup)
为了效仿结构定义,我们创建了FFI::Struct
的一个子类,并使用layout
指定字段名称和类型。
函数附加(attach_function)时,我们使用by_value
表示结构是直接传递的,而不需要通过指针进行间接传递。
Python
#!/usr/bin/env python3
import sys, ctypes
from ctypes import c_uint32, Structure
class Tuple(Structure):
_fields_ = [("x", c_uint32),
("y", c_uint32)]
def __str__(self):
return "({},{})".format(self.x, self.y)
prefix = {'win32': ''}.get(sys.platform, 'lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
lib = ctypes.cdll.LoadLibrary(prefix + "tuples" + extension)
lib.flip_things_around.argtypes = (Tuple, )
lib.flip_things_around.restype = Tuple
tup = Tuple(10, 20)
print(lib.flip_things_around(tup))
为了效仿结构定义,我们创建了一个ctypes.Structure
子类,并使用_fields_
指定字段名称和类型。
Haskell
不幸的是,Haskell 目前不支持,传递或返回任意结构。始终需要指针间接。
Node.js
const ffi = require('ffi');
const struct = require('ref-struct');
const Tuple = struct({
x: 'uint32',
y: 'uint32',
});
const lib = ffi.Library('libtuples', {
flip_things_around: [Tuple, [Tuple]],
});
const tup = new Tuple({x: 10, y: 20});
const result = lib.flip_things_around(tup);
console.log('(%d,%d)', result.x, result.y);
该ref-struct
允许我们,构建可以传递给 FFI 函数 的结构类型。
C\
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
struct IntTuple {
public uint x;
public uint y;
public static implicit operator Tuple<uint, uint>(IntTuple t)
{
return Tuple.Create(t.x, t.y);
}
public static implicit operator IntTuple(Tuple<uint, uint> t)
{
return new IntTuple { x = t.Item1, y = t.Item2 };
}
};
class Tuples
{
[DllImport("tuples")]
private static extern IntTuple flip_things_around(IntTuple t);
public static Tuple<uint, uint> FlipThingsAround(Tuple<uint, uint> t)
{
return flip_things_around(t);
}
static public void Main()
{
var tuple = Tuple.Create(10u, 20u);
var newTuple = Tuples.FlipThingsAround(tuple);
Console.WriteLine($"({newTuple.Item1},{newTuple.Item2})");
}
}
为了效仿 元组结构定义,我们创建了一个struct
,使用StructLayout
属性,并将布局定义为顺序sequential
。 我们还提供了一些隐式转换操作,使类型之间的转换无缝连接。
Julia
#!/usr/bin/env julia
using Libdl
libname = "tuples"
if !Sys.iswindows()
libname = "lib$(libname)"
end
lib = Libdl.dlopen(libname)
flipthingsaround_sym = Libdl.dlsym(lib, :flip_things_around)
struct Tuple
x::UInt32
y::UInt32
end
flipthingsaround(t:: Tuple) = ccall(
flipthingsaround_sym,
Tuple, (Tuple,),
t)
initial = Tuple(10, 20)
newtuple = flipthingsaround(initial)
println("($(newtuple.x),$(newtuple.y))")
使用完全相同的字段布局定义的 Julia 结构类型,已与 C 的数据编排兼容。由于所有字段都是isbits
,之后自然是Tuple
类型。这是因为,它存储每个内联内容,并将按值传递给原生函数。