Rust是否支持使用泛型返回类型的闭包?例如,我想写这样的东西:
let get<T: FromValue> = |s: &str| -> Option<T> { ... }
但是这种语法显然是错误的。
我正在尝试做什么
我正在使用rust-mysql-simple,我正在为from_row
结构编写User
方法,以便从数据库行构建用户。
库没有提供(据我所知)一种按列名查找查询结果行值的方法。所以要解决这个问题,我的方法看起来像(这个编译并正常工作):
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<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> { ... }
也很好,但没有帮助减少冗长。
答案 0 :(得分:8)
不,AFAIK你不能。我的意思是,你可以定义一个通用的闭包,你不能做的是创建一个带有通用左侧的let绑定。
你提到重写的fn get<T>
经历单变化,即在编译时,rustc为每个用于调用它的实际get
生成不同版本的T
。当您分配get
(let a = get(...)
)的结果时,该结果具有具体的类型和大小。
let
绑定不会被单态化,因此您不能拥有let a<T> = ...
并且编译器为您生成了不同版本的a
。
我认为可以实现这一点的是引入更高级别的类型,这是Rust非常需要但尚未完全充实的新功能之一。它们可以让你写出类似的东西:
// does not work as of Rust 1
let a = for<T> |s: &str, t: T| {...}
即。返回一个闭包,我稍后可以用T进行参数化(这就是你要求的)。
答案 1 :(得分:2)
闭包类型是匿名的,所以你将无法将其写下来,并且似乎编译器无法推断它,所以没有运气。
但是你有什么特别的理由要使用闭包吗?如果我正确地理解了你的问题,你只需使用这个函数来分解一些重复的动作,而你实际上并没有传递它。因此,内部fn
应该可以正常工作。缺点是你必须传递闭包自动捕获的所有值。
就像那样(这个例子仍然非常复杂,所以我没有尝试编译它):
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)
}
}