Mi piacerebbe poter passare una funzione generica ad un'altra funzione (in questo caso una chiusura), senza perdere la "genericità" della funzione passata. Dal momento che è una dichiarazione piuttosto contorto, ecco un esempio:Pass Funzione generica come argomento
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)
});
}
Questo non compilerà, perché il valore della input
è di tipo inferenced e non più generico.
errore completa:
<anon>:14:15: 14:19 error: mismatched types:
expected `_`,
found `_`
(expected integral variable,
found floating-point variable) [E0308]
<anon>:14 input(10.0)
^~~~
E 'possibile una cosa del genere a Rust?
edit:
Sulla base delle soluzioni di data, ho usato quanto segue per risolvere un problema simile:
#![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)
});
}
link parco giochi di ruggine: https://play.rust-lang.org/?code = uso% 20std% 3A% 3Afmt% 3A% 3ADebug% 3B% 0A% 0Afn% 20Test% 3CF% 2C% 20I% 3A% 20Debug% 3E (gen% 3A% 20F)% 20where% 20F% 3A% 20Fn (fn (I)% 20-% 3E% 20I)% 20-% 3E% 20I% 20% 7B% 0A% 20% 20% 20% 20fn% 20input% 3CI% 3A% 20Debug% 3E (x% 3A% 20I)% 20-% 3E% 20I% 20% 7B% 0A% 20% 20% 20% 20% 20% 20% 20% 20x% 0A% 20% 20% 20% 20% 7D% 0A% 20% 20% 20% 20 % 0A% 20% 20% 20% 20println! (% 22% 7B% 3A% 3F% 7D% 22% 2C% 20gen (input))% 3B% 0A% 7D% 0A% 0Afn% 20main()% 20% 7B % 0A% 20% 20% 20% 20Test (% 7Cinput% 7C% 20% 7B% 0A% 20% 20% 20% 20% 20% 20% 20% 20input (10)% 3B% 0A% 20% 20% 20 % 20% 20% 20% 20% 20input (10,0)% 0A% 20% 20% 20% 20% 7D)% 3B% 0A% 7D & versione = stable & backtrace = 0 – dpzmick
Non sono ... sicuro che funzionerebbe mai? Stai chiamando 'test' che sarà monomorfizzato per essere u32 in base all'inferenza della prima chiamata alla chiusura' gen'. Se ne vuoi uno separato, dovrai chiamare 'test' di nuovo .. separatamente. Sto "compilando" questo nella mia testa e non vedo come sarebbe possibile in questa o in altre lingue, perché l'inferenza si abbassa. Forse ho sbagliato comunque. –