假设有一个参数数组需要在 SQL 查询中使用。每个参数必须是一个
&dyn ToSql
,这已经为&str
实现了。
需要将对象同时用作
&dyn ToSql
和 &str
,如下面的示例所示,需要实现 Display
才能打印出来。
let params = ["a", "b"];
// this works but allocates
// let tx_params = ¶ms
// .iter()
// .map(|p| p as &(dyn ToSql + Sync))
// .collect::<Vec<_>>();
// this is ideal, doesn't allocate on the heap, but doesn't work
params.map(|p| p as &(dyn ToSql + Sync));
// this has to compile, so can't just crate `params` as [&(dyn ToSql + Sync)] initially
println!("Could not insert {}", params);
错误:
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `str: ToSql` is not satisfied
--> src/main.rs:14:20
|
14 | params.map(|p| p as &(dyn ToSql + Sync));
| ^ the trait `ToSql` is not implemented for `str`
|
= help: the following implementations were found:
<&'a str as ToSql>
= note: required for the cast to the object type `dyn ToSql + Sync`
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> src/main.rs:14:20
|
14 | params.map(|p| p as &(dyn ToSql + Sync));
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
= note: required for the cast to the object type `dyn ToSql + Sync`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors
特征
ToSql
没有为str
实现,但它是为&str
实现的,但是我们借用checked不会让我们借用p
,即使我们没有对数据做任何事情,除了将其转换为新类型之外。
我同意@Caesar 对此的看法,但是实际上你可以在没有堆分配的情况下做到这一点。
<[T; N]>::each_ref()
(此方法将 &[T; N]
转换为 [&T; N]
):
params.each_ref().map(|p| p as &(dyn ToSql + Sync));
游乐场。
我一个月前为此奋斗过,我的一般建议是:不要打扰。实际查询比分配重得多。
情况有点混乱,因为你需要一个
&ToSql
,但是ToSql
是为&str
实现的,所以你需要两个数组:一个
[&str]
和一个[&ToSql]
,其元素引用 &str
s - 所以 [&ToSql]
的内容是双重引用。我认为没有一种简单的方法可以在不分配的情况下实现这一目标。 (let params: [&&str; 2] = params.iter().collect::<Vec<_>>().try_into().unwrap();
有效,分配可能会被优化。存在夜间或不安全的方式,请参阅@ChayimFriedman的答案。)
在这种情况下,您可以通过最初声明来解决:
let params = [&"a", &"b"];
通过使用迭代器,而不是数组:
let iter = params.iter().map(|p| p as &(dyn ToSql + Sync));
client.query_raw("select * from foo where id in ?", iter);
就我而言,我无法执行类似的操作,因为我使用的是执行,而不是查询,并且
execute_raw
仅存在于 tokio-postgres
上,而不存在于 postgres
上。所以要小心这些陷阱。