可以定义通用闭包吗? [英] Possible to define generic closure?

查看:39
本文介绍了可以定义通用闭包吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Rust 是否支持具有泛型返回类型的闭包?例如,我想写这样的东西:

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

let get<T: FromValue> = |s: &str| -> Option<T> { ... }

但这种语法显然是错误的.

But that syntax is clearly wrong.

我想做什么

我正在使用 rust-mysql-simple,我正在写我的 User 结构的 from_row 方法,用于从数据库行构建用户.

I'm working with rust-mysql-simple, and I'm writing a from_row method for my User struct, to build a user from a database row.

库不提供(据我所知)按列名查找查询结果行值的方法.所以为了解决这个问题,我的方法看起来像(这可以编译并正常工作):

The library doesn't provide (as far as I can tell) a way to look up query result row values by column name. So to work around this, my method looks like (this compiles and works correctly):

fn from_row(result: &QueryResult, row: Vec<Value>) -> User {

    let mut map: HashMap<_, _> = row.into_iter().enumerate().collect();

    let mut get = |s: &str|  {
        result.column_index(s)
           .and_then(|i| map.remove(&i) )
    };

    User {
        id: get("id").and_then(|x| from_value_opt(x).ok() )
    }
}

这里,result 是一个包含查询列名信息的对象(用于查找列名的列索引),row 包含有序的来自查询结果行的值.from_value_opt 是库提供的一个方法,它接受一个 Value 并返回一个 Result.该值被强制为字段的类型.

Here, result is an object that contains information about the query's column names (used to find the column index for a column name), and the row contains the ordered values from a query result row. from_value_opt is a method provided by the library that takes a Value and returns a Result<T, MyError>. The value is coerced to the field's type.

我试图将 .and_then(|x| from_value_opt(x).ok() ) 移动到 get 闭包中只是为了清理一些代码.但是,当我这样做时,闭包返回类型被解释为第一次出现 get 调用的结果.

I was trying to move the .and_then(|x| from_value_opt(x).ok() ) into the get closure just to clean up the code some. However, when I do so, the closure return type is interpreted to be the result of the first occurrence of the get call.

我将闭包重写为嵌套方法,如下所示:

I rewrote the closure as a nested method that looks like:

fn get<T: FromValue>(r: &QueryResult, m: &mut HashMap<usize, Value>, s: &str)
    -> Option<T> { ... }

这也工作得很好,但并没有帮助减少冗长.

which also worked fine, but didn't help cutting the verbosity much.

推荐答案

不,AFAIK 你不能.我的意思是,你可以定义一个泛型闭包,你不能做的是创建一个带有泛型左侧的 let 绑定.​​

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.

fn get,正如你提到的重写,经历了单态化,即在编译它时,rustc 为每个实际的 get 生成不同版本的 getcode>T 用于调用它.到您分配 get (let a = get(...)) 的结果时,该结果具有具体的类型和大小.

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.

一个 let 绑定不会被单态化,所以你不能有一个 let a<T>= ... 并让编译器为您生成不同版本的 a.

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.

我认为可能实现这一点的是引入更高级的类型,这是 Rust 非常需要但尚未完全充实的新功能之一.它们将使您能够编写如下内容:

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| {...}

即返回一个闭包,我稍后可以使用 T 对其进行参数化(这正是您所要求的).

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

这篇关于可以定义通用闭包吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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