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

时间:2018-06-19 20:47:05

标签: 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));
}

1 个答案:

答案 0 :(得分:1)

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

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

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

通常,Rust可以推断函数的类型参数。参数类型通常更容易推断,因为那里有所需类型的值。甚至C ++都可以推断参数类型!返回类型很难推断,因为它们取决于调用该函数的上下文,但是Rust经常也可以推断这些类型。

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

T

很明显,参数是整数,因为它是文字,并且就在那。有一些规则可以确定它可能是什么整数类型,但是在这种情况下,它必须为format!("{}.jpg", row.get(0)) ,因为这是实现usize特征的唯一一个。

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

FromSql

幸运的是,Rust具有将函数参数显式传递给函数的语法,因此您不必依赖于其类型推断。 Shepmaster在this answer中对类似问题做了很好的解释。直接跳到答案,您可以编写error[E0283]: type annotations required: cannot resolve `_: postgres::types::FromSql` 仅指定第二种类型的参数,然后对第一种类型的参数进行推断。

您特别要求使用一种更加惯用的方式来指定类型,我认为您已经拥有的惯用了。使用显式类型参数,读者仍然需要了解row.get::<_, String>(0)的签名,才能知道get将是返回类型。第二种类型的参数并不总是返回类型的情况,而且很容易混淆并以错误的顺序指定它们。通过对结果进行命名和类型注释,您可以明显看出类型注释所指的是什么值。

String

如果您确实想以Shepmaster建议的更实用的样式编写代码,则仍然可以使用以下样式:

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

并在符合您口味的情况下打破“单线”。