可以定义泛型闭包吗?

Jac*_*own 13 rust

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

let get<T: FromValue> = |s: &str| -> Option<T> { ... }
Run Code Online (Sandbox Code Playgroud)

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

我想做什么

我正在使用rust-mysql-simple,我正在from_row为我的Userstruct 编写一个方法,从数据库行构建一个用户.

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

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)

这也很好,但没有帮助减少冗长.

Pao*_*lla 8

不,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进行参数化(这就是你所要求的).


kir*_*gin 7

闭包类型是匿名的,因此您无法将其写下来,并且编译器似乎无法推断出它,所以运气不好。

\n\n

但是您想使用闭包有什么特殊原因吗?如果我正确理解你的问题,你只需使用这个函数来分解一些重复的动作,而你实际上不会传递它。于是,一个内在的fn应该可以正常工作。缺点是您\xe2\x80\x99必须传递过去由闭包自动捕获的所有值。

\n\n

它会是这样的(这个例子仍然相当复杂,所以我没有\xe2\x80\x99t尝试编译它):

\n\n
fn 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

  • 感谢你的回答。是的,这就是为什么我想使用闭包——这样我就不必传递这些值。然而,这就是我最终选择的方式(请参阅我的问题的最后部分)。 (2认同)