Possible to define generic closure?

后端 未结 2 1127
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-07 18:13

Does Rust support closures with generic return types? For example, I want to write something like this:

let get = |s: &str| -> Opt         


        
相关标签:
2条回答
  • 2021-01-07 18:39

    No, AFAIK you can't. I mean, you can define a generic closure, what you can't do is create a let binding with a generic left-hand side.

    A fn get<T>, as the one you mention rewriting, undergoes monomorphisation, i.e. when compiling it, rustc generates a different version of get for every actual T that is used to call it. By the time you assign the result of that get (let a = get(...)), that result has a concrete type and size.

    A let binding does not get monomorphised, so you can't have a let a<T> = ... and have a different version of a generated for you by the compiler.

    What I think might enable this is the introduction of higher-kinded types, which is one of the highly desired but not yet fully fleshed out new features for Rust. They would enable you to write something like:

    // does not work as of Rust 1
    let a = for<T> |s: &str, t: T| {...}
    

    i.e. return a closure that I can later parametrize with a T (which is what you're asking for).

    0 讨论(0)
  • 2021-01-07 18:40

    The closure type is anonymous, so you won’t be able to write it down, and seems that the compiler won’t be able to infer it, so no luck.

    But is there any particular reason you want to use a closure? If I understood your question correctly, you just use this function to factor out some repeating actions, and you are not actually going to pass it around. Thus, an inner fn should work just fine. The downside is that you’ll have to pass all the values that used to be automatically captured by your closure.

    It would be something like that (the example is still pretty complex, so I didn’t try to compile it):

    fn from_row(result: &QueryResult, row: Vec<Value>) -> User {
        let mut map: HashMap<_, _> = row.into_iter().enumerate().collect();
    
        fn get<T: FromValue>(s: &str, result: &QueryResult, map: &mut HashMap<_, _>)
           -> T {
            result.column_index(s)
                .and_then(|i| map.remove(&i))
                .and_then(|x| from_value_opt(x)).ok()
        };
    
        User {
            id: get("id", &result, &mut map)
        }
    }
    
    0 讨论(0)
提交回复
热议问题