将泛型函数作为参数传递 [英] Pass Generic Function as argument

查看:53
本文介绍了将泛型函数作为参数传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够将通用函数传递给另一个函数(在本例中为闭包),而不会失去通用性"传递的函数.由于这是一个相当复杂的陈述,这里有一个例子:

I would like to be able to pass a generic function to another function (in this case a closure), without losing the "genericness" of the passed function. Since that's a pretty convoluted statement, here's an example:

use std::fmt::Debug;

fn test<F, I: Debug>(gen: F) where F: Fn(fn(I) -> I) -> I {
    fn input<I: Debug>(x: I) -> I {
        x
    }
    
    println!("{:?}", gen(input));
}

fn main() {
    test(|input| {
        input(10);
        input(10.0)
    });
}

这不会编译,因为 input 的值是类型推断的,不再是通用的.

This will not compile, because the value of input is type inferenced and no longer generic.

完全错误:

<anon>:14:15: 14:19 error: mismatched types:
 expected `_`,
    found `_`
(expected integral variable,
    found floating-point variable) [E0308]
<anon>:14         input(10.0)
                        ^~~~

这样的事情在 Rust 中可能吗?

Is such a thing possible in rust?

根据给出的解决方案,我使用以下方法解决了类似的问题:

Based on the solutions given, I've used the following to solve a similar problem:

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

use std::ops::Fn;
use std::ops::Add;
use std::ops::FnMut;

use std::fmt::Debug;

struct Builder;

impl Builder {
    pub fn build<A: Add<B>, B: Add<A>>(&self) -> fn(A, B) -> <A as std::ops::Add<B>>::Output {
        fn c<A: Add<B>, B: Add<A>>(a: A, b: B) -> <A as std::ops::Add<B>>::Output {
            a + b
        }
        
        return c;
    }
}

impl<A: Add<B>, B: Add<A>> Fn<(A, B)> for Builder {
    extern "rust-call" fn call(&self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
        let (a1, a2) = args;
        self.build()(a1, a2)
    }
}

impl<A: Add<B>, B: Add<A>> FnMut<(A, B)> for Builder {
    extern "rust-call" fn call_mut(&mut self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
        let (a1, a2) = args;
        self.build()(a1, a2)
    }
}

impl<A: Add<B>, B: Add<A>> FnOnce<(A, B)> for Builder {
    type Output = <A as std::ops::Add<B>>::Output;
    extern "rust-call" fn call_once(self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
        let (a1, a2) = args;
        self.build()(a1, a2)
    }
}

fn test<F, I: Debug>(gen: F) where F: Fn(Builder) -> I {
    let b = Builder;
    println!("{:?}", gen(b));
}

fn main() {
    test(|builder| {
        builder(10, 10);
        builder(10.1, 10.0)
    });
}

推荐答案

如前所述,不幸的是调用在调用现场是单态化的,所以不能传递泛型函数,只能传递泛型的单态化版本功能.

As has been mentioned, unfortunately the call is monomorphized at the call site, so you cannot pass a generic function, you can only pass a monomorphized version of the generic function.

可以传递的是一个函数builder:

use std::fmt::Debug;

struct Builder;

impl Builder {
    fn build<I: Debug>(&self) -> fn(I) -> I {
        fn input<I: Debug>(x: I) -> I { x }
        input
    }
}

fn test<F, T: Debug>(gen: F)
    where F: Fn(Builder) -> T
{
    let builder = Builder;
    println!("{:?}", gen(builder));
}

fn main() {
    test(|builder| {
        builder.build()(10);
        builder.build()(10.0)
    });
}

Builder 能够按需生成 input 的实例.

The Builder is able to generate instances of input on demand.

这篇关于将泛型函数作为参数传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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