可以定义通用闭包吗? [英] Possible to define generic closure?
问题描述
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
生成不同版本的 get
code>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屋!