Rust是否支持使用泛型返回类型的闭包?例如,我想写这样的东西:
let get<T: FromValue> = |s: &str| -> Option<T> { ... }
Run Code Online (Sandbox Code Playgroud)
但这种语法显然是错误的.
我想做什么
我正在使用rust-mysql-simple,我正在from_row
为我的User
struct 编写一个方法,从数据库行构建一个用户.
该库不提供(据我所知)一种按列名查找查询结果行值的方法.所以要解决这个问题,我的方法看起来像(这个编译并正常工作):
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() )
}
}
Run Code Online (Sandbox Code Playgroud)
这result
是一个对象,它包含有关查询列名的信息(用于查找列名的列索引),并row
包含查询结果行中的有序值.from_value_opt
是一个由库提供的方法,它接受Value
并返回一个Result<T, MyError>
.该值被强制转换为字段的类型.
我试图移动.and_then(|x| from_value_opt(x).ok() )
到get
关闭只是为了清理代码一些.但是,当我这样做时,闭包返回类型被解释为第一次出现get
调用的结果.
我将闭包重写为嵌套方法,如下所示:
fn get<T: FromValue>(r: &QueryResult, m: &mut HashMap<usize, Value>, s: &str)
-> Option<T> { ... }
Run Code Online (Sandbox Code Playgroud)
这也很好,但没有帮助减少冗长.
不,AFAIK你不能.我的意思是,你可以定义一个通用的闭包,你不能做的就是创建一个带有通用左侧的let绑定.
A fn get<T>
,就像你提到的重写一样,经历单变量,即在编译时,rustc get
为每个T
用于调用它的实际生成不同的版本.当您分配that get
(let a = get(...)
)的结果时,该结果具有具体的类型和大小.
一个let
结合没有得到monomorphised,所以你不能拥有let a<T> = ...
,并有不同版本的a
编译器为您生成.
我认为可以实现这一点的是引入更高级的类型,这是Rust非常期望但尚未完全充实的新功能之一.他们会让你写下这样的东西:
// does not work as of Rust 1
let a = for<T> |s: &str, t: T| {...}
Run Code Online (Sandbox Code Playgroud)
即返回一个闭包,我稍后可以用T进行参数化(这就是你所要求的).
闭包类型是匿名的,因此您无法将其写下来,并且编译器似乎无法推断出它,所以运气不好。
\n\n但是您想使用闭包有什么特殊原因吗?如果我正确理解你的问题,你只需使用这个函数来分解一些重复的动作,而你实际上不会传递它。于是,一个内在的fn
应该可以正常工作。缺点是您\xe2\x80\x99必须传递过去由闭包自动捕获的所有值。
它会是这样的(这个例子仍然相当复杂,所以我没有\xe2\x80\x99t尝试编译它):
\n\nfn from_row(result: &QueryResult, row: Vec<Value>) -> User {\n let mut map: HashMap<_, _> = row.into_iter().enumerate().collect();\n\n fn get<T: FromValue>(s: &str, result: &QueryResult, map: &mut HashMap<_, _>)\n -> T {\n result.column_index(s)\n .and_then(|i| map.remove(&i))\n .and_then(|x| from_value_opt(x)).ok()\n };\n\n User {\n id: get("id", &result, &mut map)\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n