在解析 Postgres 结果时键入格式所需的注释!

  • 本文关键字:格式 注释 Postgres 结果 rust
  • 更新时间 :
  • 英文 :


我有一些代码应该从数据库中获取图像文件名并将它们添加到向量中。

extern crate postgres;
use postgres::{Connection, TlsMode};
fn main() {
let conn = Connection::connect(
"postgres://postgres:password@localhost:5432/test",
TlsMode::None,
).unwrap();
let mut filenames = Vec::new();
if let Ok(filename_results) = conn.query("SELECT filename FROM images", &[]) {
for row in &filename_results {
filenames.push(format!("{}.jpg", row.get(0)));
}
}
println!("{:?}", filenames);
}

此操作失败,并显示:

error[E0283]: type annotations required: cannot resolve `_: postgres::types::FromSql`
--> src/main.rs:14:54
|
14 |                 filenames.push(format!("{}.jpg", row.get(0)));
|                                                      ^^^

我不明白为什么 Rust 无法在这种情况下找出类型,尽管我已经找到了一种使其工作的方法。我想知道告诉format!()它应该期待什么类型的最简单/惯用的方法是什么,以及为什么 row.get(0( 不需要类型注释,除非我打了一个格式!(( 周围。这是我对解决方案的最佳尝试:

for row in &filename_results {
let filename: String = row.get(0);
filenames.push(format!("{}.jpg", filename));
}

让我们看看你正在调用的函数的签名:

fn get<I, T>(&self, idx: I) -> T 
where
I: RowIndex + Debug,
T: FromSql,

也就是说,这个函数实际上有两个类型参数,IT。它使用I作为要与之编制索引的类型。您传递的参数具有此类型。T是返回类型。约束(where子句(在这里并不重要,但它们指定参数类型I必须是 postgres 可以用作行索引的东西,而返回类型T必须是 postgres 可以从 SQL 结果创建的东西。

通常,Rust 可以推断函数的类型参数。参数类型通常更容易推断,因为那里有一个所需类型的值。即使是C++也可以推断出参数类型!返回类型更难推断,因为它们依赖于调用函数的上下文,但 Rust 通常也可以推断出这些类型。

让我们看一下您的函数调用及其使用的上下文:

format!("{}.jpg", row.get(0))

很明显,参数是一个整数,因为它是一个文字,它就在那里。有一些规则可以确定它可能是什么整数类型,但在这种情况下,它必须usize,因为这是唯一实现RowIndex特征的规则。

但是您期望什么返回类型?format!几乎可以采用任何类型,因此编译器无法知道get需要返回什么。它所知道的是,T必须具有FromSql特征。这是错误消息告诉您的内容:

error[E0283]: type annotations required: cannot resolve `_: postgres::types::FromSql`

幸运的是,Rust 有一个将函数参数显式传递给函数的语法,因此您不必依赖其类型推断。Shepmaster在对类似问题的回答中对此进行了很好的解释。直接跳到答案,您可以编写row.get::<_, String>(0)以仅指定第二个类型参数,并让推理处理第一个类型参数。

您特别要求一种更惯用的方式来指定类型,我认为您已经拥有的更惯用。使用显式类型参数,读者仍然需要了解get的签名才能知道String将是返回类型。第二个类型参数并不总是返回类型,并且很容易混淆并以错误的顺序指定它们。通过命名和类型批注结果,可以清楚地看到类型批注所引用的值。

let filename: String = row.get(0);
filenames.push(format!("{}.jpg", filename));

如果你确实想用Shepmaster建议的更函数化的风格编写代码,你仍然可以使用以下风格:

let filenames = filename_results.map(|row| { let f: String = row.get(0); format!("{}.jpg", f) }).collect();

如果适合您的口味,请打破跨行的"单行"。

最新更新