Generics 如何将带有泛型的闭包传递给函数而不使该函数泛型?
我有一个使用枚举的函数来应用二进制函数。这是为口译员准备的:Generics 如何将带有泛型的闭包传递给函数而不使该函数泛型?,generics,rust,closures,Generics,Rust,Closures,我有一个使用枚举的函数来应用二进制函数。这是为口译员准备的: use std::ops::*; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum Scalar { I64(i64), I32(i32), //many many others } pub trait TMath: Add + Mul + Sized {} //mark numerical types impl<T: Add + Mul&
use std::ops::*;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Scalar {
I64(i64),
I32(i32),
//many many others
}
pub trait TMath: Add + Mul + Sized {} //mark numerical types
impl<T: Add + Mul> TMath for T {}
fn add<T: TMath>(x: T, y: T) -> <T as Add>::Output {
x + y
}
pub type NatBinExpr<T: TMath> = Fn(&T, &T) -> T;
但也要使其适用于任意二进制函数:
let result = bin_op(Scalar::concat, &Scalar::I32(1), &Scalar::I32(2));
然而,我还没有找到一种方法可以在不使用bin_op
generic的情况下通过闭包:
fn bin_op(apply: &NatBinExpr???, x: &Scalar, y: &Scalar) -> Scalar {
match (x, y) {
(Scalar::I64(a), Scalar::I64(b)) => Scalar::I64(apply(a, b)),
(Scalar::I32(a), Scalar::I32(b)) => Scalar::I32(apply(a, b)),
}
}
使bin_op
通用是不对的bin_op
对标量进行操作,但内部操作是通用的
我最初谈论函数类型基本上有两种不同的方式:
- 指针:
fn(A,B)->C
- 特征:
,Fn(A,B)->C
,FnMut(A,B)->C
FnOnce(A,B)->C
apply
的参数和结果类型是什么
视情况而定。
从您的示例中,我们可以看到,[i64,i32,…]
中的T
是FnOnce(T,T)->T
这不是一种类型,而是多种类型。因此,它需要的不是单一的功能,而是多种功能;或者可能是一个函数对象实现了一次
fn多次
函数对象路由仅在夜间可用,并且需要大量的样板文件(宏会有帮助):
#![特征(fn_特征)]
#![功能(未固定的_闭包)]
使用std::ops::*;
#[派生(调试、克隆、PartialEq、PartialOrd)]
pub枚举标量{
I64(I64),
I32(I32),
//许多其他的
}
pub-trait-TMath:Add+Mul+size{}//标记数字类型
T{}的impl TMath
结构加法器;
加法器的impl-FnOnce{
类型输出=i64;
外部“锈调用”fn调用一次(self,args:(i64,i64))->i64{
参数0+参数1
}
}
加法器的impl-FnMut{
外部“锈调用”fn调用_mut(&mut self,args:(i64,i64))->i64{
参数0+参数1
}
}
加法器的impl-Fn{
外部“锈调用”fn调用(&self,args:(i64,i64))->i64{
参数0+参数1
}
}
加法器的impl-FnOnce{
类型输出=i32;
外部“锈调用”fn调用一次(self,args:(i32,i32))->i32{
参数0+参数1
}
}
加法器的impl-FnMut{
外部“锈调用”fn调用_mut(&mut self,args:(i32,i32))->i32{
参数0+参数1
}
}
加法器的impl-Fn{
外部“锈调用”fn调用(&self,args:(i32,i32))->i32{
参数0+参数1
}
}
fn bin_op(应用:&F,x:Scalar,y:Scalar)->Scalar
哪里
F:Fn(i64,i64)->i64,
F:Fn(i32,i32)->i32,
{
匹配(x,y){
(标量::I64(a),标量::I64(b))
=>标量::I64((应用为&Fn(I64,I64)->I64)(a,b)),
(标量::I32(a),标量::I32(b))
=>标量::I32((应用as&Fn(I32,I32)->I32)(a,b)),
_=>无法访问!(),
}
}
fn main(){
让结果=bin_op(&加法器,标量::I32(1),标量::I32(2));
println!(“{:?}”,结果);
}
看起来您需要更高级的类型来表达这一点,而rust目前不支持这一点。这是冗长还是比正常方式更详细?如果它不能在没有每个操作符实现的情况下崩溃为只通过(A,B)->C,那么我就看不出这有什么意义。@mamcx:它肯定是在冗长的方面,本质上归结为生锈,不支持重载。老实说,在这一点上,我会使用一个定制的
特征BinOp{fn on_i64(&self,i64,i64)->i64;fn on_i32(&self,i32,i32)->i32;…}
(每种类型都有一个方法),然后为加法器
,乘法器
,等等实现它。@mamcx您可能会创建一个宏规则代码>宏以最小化重复。
fn bin_op(apply: &NatBinExpr???, x: &Scalar, y: &Scalar) -> Scalar {
match (x, y) {
(Scalar::I64(a), Scalar::I64(b)) => Scalar::I64(apply(a, b)),
(Scalar::I32(a), Scalar::I32(b)) => Scalar::I32(apply(a, b)),
}
}
#![feature(fn_traits)]
#![feature(unboxed_closures)]
use std::ops::*;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Scalar {
I64(i64),
I32(i32),
//many many others
}
pub trait TMath: Add + Mul + Sized {} //mark numerical types
impl<T: Add + Mul> TMath for T {}
struct Adder;
impl FnOnce<(i64, i64)> for Adder {
type Output = i64;
extern "rust-call" fn call_once(self, args: (i64, i64)) -> i64 {
args.0 + args.1
}
}
impl FnMut<(i64, i64)> for Adder {
extern "rust-call" fn call_mut(&mut self, args: (i64, i64)) -> i64 {
args.0 + args.1
}
}
impl Fn<(i64, i64)> for Adder {
extern "rust-call" fn call(&self, args: (i64, i64)) -> i64 {
args.0 + args.1
}
}
impl FnOnce<(i32, i32)> for Adder {
type Output = i32;
extern "rust-call" fn call_once(self, args: (i32, i32)) -> i32 {
args.0 + args.1
}
}
impl FnMut<(i32, i32)> for Adder {
extern "rust-call" fn call_mut(&mut self, args: (i32, i32)) -> i32 {
args.0 + args.1
}
}
impl Fn<(i32, i32)> for Adder {
extern "rust-call" fn call(&self, args: (i32, i32)) -> i32 {
args.0 + args.1
}
}
fn bin_op<F>(apply: &F, x: Scalar, y: Scalar) -> Scalar
where
F: Fn(i64, i64) -> i64,
F: Fn(i32, i32) -> i32,
{
match (x, y) {
(Scalar::I64(a), Scalar::I64(b))
=> Scalar::I64((apply as &Fn(i64, i64) -> i64)(a, b)),
(Scalar::I32(a), Scalar::I32(b))
=> Scalar::I32((apply as &Fn(i32, i32) -> i32)(a, b)),
_ => unreachable!(),
}
}
fn main() {
let result = bin_op(&Adder, Scalar::I32(1), Scalar::I32(2));
println!("{:?}", result);
}