rust - 格式所需的类型注释!解析 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) 不需要类型注释,除非我打一个format!() 围绕它。这是我对解决方案的最佳尝试:

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 在 this answer 中对此做了很好的解释。到一个类似的问题。直接跳到答案,你可以写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();

如果适合您的口味,可以跨行打破“一行”。

关于rust - 格式所需的类型注释!解析 postgres 结果时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50936699/

相关文章:

rust - 如何防止ruSTLib在aarch64上引用软 float 函数?

arrays - 将数组从 Julia 发送到 Rust(使用 "ccall")

rust - 在rust-webpack-template中的 `blocking`中找不到 `reqwest`

rust - 如何在不变成FnOnce的情况下将共享变量从 rust Fn中删除?

rust - 返回非平凡的 gstreamer "pad callbacks"作为盒装闭包

rust - 链接到其他库时是否可以将单个rust文件作为脚本运行而无需生成 cargo 项目

scala - 不能将 futures-util crate 与 Actix 一起使用,因为特征 Future 未实现

generics - 取决于特征的通用实现

generics - "Overflow evaluating the requirement"但这种递归根本不应该发生

rust - Rust 1.3.0 中的猜谜游戏