rust - postgres Rust 中 get 方法的生命周期
问题描述
一些背景(随意跳过):
我对 Rust 很陌生,我来自 Haskell 背景(以防万一让您了解我可能有的任何误解)。
我正在尝试编写一个程序,给定来自数据库的大量输入,可以创建可自定义的报告。为此,我想创建一个Field
可以以某种 DSL 样式组合的数据类型。在 Haskell 中,我的直觉是创建Field
一个实例,Functor
这样Applicative
就可以编写这样的东西:
type Env = [String]
type Row = [String]
data Field a = Field
{ fieldParse :: Env -> Row -> a }
instance Functor Field where
fmap f a = Field $
\env row -> f $ fieldParse a env row
instance Applicative Field where
pure = Field . const . const
fa <*> fb = Field $
\env row -> (fieldParse fa) env row
$ (fieldParse fb) env row
oneField :: Field Int
oneField = pure 1
twoField :: Field Int
twoField = fmap (*2) oneField
tripleField :: Field (Int -> Int)
tripleField = pure (*3)
threeField :: Field Int
threeField = tripleField <*> oneField
实际问题:
我知道在 Rust中实现Functor
和trait是很尴尬的,所以我只是实现了适当的函数而不是实际定义特征(这一切都编译得很好)。这是一个非常简化的Rust 实现,没有任何or东西。Applicative
Field
Field
Functor
Applicative
use std::result;
use postgres::Row;
use postgres::types::FromSql;
type Env = Vec<String>;
type FieldFunction<A> = Box<dyn Fn(&Env, &Row) -> Result<A, String>>;
struct Field<A> {
field_parse: FieldFunction<A>
}
我可以轻松地创建一个函数,它只是从输入字段中获取值并Field
使用它创建一个报告:
fn field_good(input: u32) -> Field<String> {
let f = Box::new(move |_: &Env, row: &Row| {
Ok(row.get(input as usize))
});
Field { field_parse: f }
}
但是当我尝试使这个多态而不是使用时,String
我得到了一些我不明白的非常奇怪的生命周期错误:
fn field_bad<'a, A: FromSql<'a>>(input: u32) -> Field<A> {
let f = Box::new(move |_: &Env, row: &Row| {
Ok(row.get(input as usize))
});
Field { field_parse: f }
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/test.rs:36:16
|
36 | Ok(row.get(input as usize))
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 35:22...
--> src/test.rs:35:22
|
35 | let f = Box::new(move |_: &Env, row: &Row| {
| ______________________^
36 | | Ok(row.get(input as usize))
37 | | });
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/test.rs:36:12
|
36 | Ok(row.get(input as usize))
| ^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 34:14...
--> src/test.rs:34:14
|
34 | fn field_bad<'a, A: FromSql<'a>>(input: FieldId) -> Field<A> {
| ^^
note: ...so that the types are compatible
--> src/test.rs:36:16
|
36 | Ok(row.get(input as usize))
| ^^^
= note: expected `FromSql<'_>`
found `FromSql<'a>`
任何帮助解释这个错误实际上是什么或如何解决它都将不胜感激。我包含了 Haskell 的东西,这样我的设计意图就很清楚了,这样如果问题是我使用的编程风格在 Rust 中并不真正适用,那么可以向我指出。
编辑:忘记包含文档的链接postgres::Row::get
以防万一。他们可以在这里找到。
解决方案
更高等级的特征界限
我不熟悉正在使用的 postgresql crate,因此我无法就代码所采用的方法提供任何一般性指导。
但无论如何,坚持当前实现中生命周期的直接问题,更高级别的特征界限可能是可行的。不过,我需要一个工作示例来确认这一点。
这对我来说是一个新的。我试用了您的代码,并收到了一些有趣的错误消息,表明for
在声明边界时使用了。这将我带到了Rust 参考。
所以我试了一下,它编译了。
fn field_bad<A>(input: u32) -> Field<A>
where A: for<'a> FromSql<'a>
{
let f = Box::new(move |_: &Env, row: &Row| {
Ok(row.get(input as usize))
});
Field { field_parse: f }
}
Rustnomicon 中的这一部分讨论了 HRTB。
这篇SO 帖子讨论了生命周期和更高级别的特征界限如何不同。
这里发生的事情field_bad()
是没有返回任何FromSql
实例——直接或间接通过Field
. FromSql
只是Ok(T)
闭包返回类型的一部分,它作为一个字段存在于Field
. 所以for<..>
语法允许我们提供适用于闭包在调用时返回的类型的生命周期。
推荐阅读
- jenkins - 詹金斯从 cli 创建工作
- javascript - html2canvas 的问题
- tomcat - Debian 端口开放配置有什么问题?
- c++ - 在 Qt 中注册自定义 MetaType 的别名类型
- spring-boot - 使用 bootRun 和没有 isOptimizedLaunch = false 的 springboot 应用程序(kotlin、gradle)性能低下
- c# - 从 c# 中的 datagridview 获取记录 ID 并将数据显示到另一个表单
- installation - 未在 Windows 10 操作系统中使用 WIX 引导程序安装的先决条件
- git - 如何选择一个分支上某人的所有提交并插入另一个分支?
- c# - 静态字符串的链式插值不能按预期工作
- python - Pandas - 仅将一个数据框与其自身部分合并