我有一些代码应该从数据库中获取图像文件名并将其添加到向量中。
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));
}
答案 0 :(得分:1)
让我们看看您正在调用的函数的签名:
fn get<I, T>(&self, idx: I) -> T
where
I: RowIndex + Debug,
T: FromSql,
也就是说,此函数实际上有两个类型参数,I
和T
。它使用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));
并在符合您口味的情况下打破“单线”。