Rust中的元组扩展/应用

5
我发现了关于元组展开的这个讨论,但是它是2014年的内容。
给出的示例是:
fn sum(x: i32, y: i32) -> i32 {
    x + y
}

fn prepare_args () -> (i32, i32) {
    (1, 2)
}

fn main() {
    sum(prepare_args()); // Doesn't work
}

提出的解决方案是自己编写apply函数:

fn apply<A,B,C>(f: |A,B|->C, t: (A,B)) -> C {
    let (a,b) = t;
    f(a,b)
}

fn main() {
    apply(sum, prepare_args());
}

这是目前最好的方法吗?如果是,正确的语法是什么?使用上述内容会出现一些错误,包括expected type, found|at line 1 col 20

还没有元组展开运算符吗?

3个回答

6

证明否定总是非常困难的...

据我所知,确实没有元组展开运算符。然而,Fn*特征族(Fn)接受一个参数,作为元组。

在夜间编译器上,激活一些不稳定的功能,因此您可以使用:

#![feature(fn_traits)]
#![feature(unboxed_closures)]

fn sum(x: i32, y: i32) -> i32 {
    x + y
}

fn prepare_args () -> (i32, i32) {
    (1, 2)
}

fn main() {
    let func: &Fn(i32, i32) -> i32 = &sum;
    let result = func.call(prepare_args());
    println!("{:?}", result);
}

虽然不是最理想的情况,但是在不支持可变参数的情况下,您仍然需要知道元组中元素的数量,因此值很低。


6

我不认为有一个扩展运算符。

你找到的代码来自于2014年之前的Rust 1.0版本,因此已经过时。为了使apply函数在1.0版本之后的Rust中工作,将其更改为以下内容:

fn sum(x: i32, y: i32) -> i32 {
    x + y
}

fn prepare_args() -> (i32, i32) {
    (1, 2)
}

fn apply<A, B, C, F>(f: F, t: (A, B)) -> C
    where F : Fn(A, B) -> C
{
    let (a, b) = t;
    f(a, b)
}

fn main() {
    let x = apply(sum, prepare_args());
    println!("{}", x);
}

这段代码可以在 Rust playground上正确编译和运行。

你也可以使用 f(t.0, t.1) 作为 apply 的主体,或者在参数列表中进行解构(Playground):

fn apply<A, B, C, F>(f: F, (a, b): (A, B)) -> C
    where F : Fn(A, B) -> C
{
    f(a, b)
}

3
以下是一个适用于元组大小从1到6(可增加)的apply版本(Playground):
fn main() {
    let add1 = |x| x + 1;
    let sum2 = ::std::ops::Add::add;
    let sum3 = |a, b, c| a + b + c;
    assert_eq!(apply(add1, (1,)), 2);
    assert_eq!(apply(sum2, (1, 2)), 3);
    assert_eq!(apply(sum3, (1, 2, 3)), 6);
}

#[inline(always)]
pub fn apply<Fun, In, Out>(fun: Fun, params: In) -> Out
    where ApplyImpl: Apply<Fun, In, Out>
{
    ApplyImpl::apply(fun, params)
}

pub trait Apply<Fun, In, Out> {
    fn apply(fun: Fun, params: In) -> Out;
}

pub struct ApplyImpl;

macro_rules! impl_apply {
    () => ();
    ($A:ident, $($B:ident,)*) => (
        impl_apply!{$($B,)*}

        impl<$A, $($B,)* Fun, Out> Apply<Fun, ($A, $($B),*), Out> for ApplyImpl
        where Fun: Fn($A, $($B),*) -> Out
        {
            #[allow(non_snake_case)]
            #[inline(always)]
            fn apply(fun: Fun, params: ($A, $($B),*)) -> Out {
                // use type parameters as var names...
                let ($A, $($B),*) = params;
                fun($A, $($B),*)
            }
        }
    )
}

impl_apply!{A, B, C, D, E, F,}

我在考虑为它创建一个板条箱(crate)。 如果我这样做,我会在这里放链接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接