如何在不分配堆的情况下转换切片引用的元素?
假设 SQL 查询中需要使用一组参数。每个参数必须是 &dyn ToSql
,它已针对 &str
实现。
需要将该对象同时用作 &dyn ToSql
和 &str
,如下面的示例所示,其中需要实现 Display< /code> 以便打印出来。
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
,尽管我们除了将其转换为新类型之外没有对数据执行任何操作。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我同意@Caesar 对此的看法,但是实际上您可以在没有堆分配的情况下做到这一点。
您可以使用
<[T; N]>::each_ref()
(此方法将&[T; N]
转换为[&T; N]):
游乐场。
I agree with @Caesar's take on this, however you actually can do that without heap allocations.
You can use
<[T; N]>::each_ref()
for that (this method converts&[T; N]
to[&T; N]
):Playground.
我一个月前曾为此奋斗过,我的一般建议是:不要打扰。实际的查询比分配重得多。
这种情况有点令人困惑,因为您需要一个
&ToSql
,但是ToSql
已实现&str
,因此您需要两个数组:一个[&str]
和一个[&ToSql]
,其元素引用 < code>&strs - 因此[&ToSql]
的内容是双重引用。我认为没有一种简单的方法可以在不分配的情况下实现这一目标。 (let params: [&&str; 2] = params.iter().collect::>().try_into().unwrap();
有效并且分配可能会被优化,存在夜间或不安全的方式,请参阅@ChayimFriedman的答案。)在这种情况下,您可以通过最初声明来解决:
通过使用迭代器,而不是数组:
就我而言,我无法执行类似的操作,因为我使用的是执行,而不是查询,并且
execute_raw
仅存在于tokio-postgres,但不在
postgres
上。所以要小心这些类型的陷阱。I fought this a month ago and my general recommendation is: Don't bother. The actual query is so much heavier than an allocation.
The situation is a bit confusing, because you need an
&ToSql
, butToSql
is implemented for&str
, so you need two arrays: One[&str]
, and one[&ToSql]
, whose elements reference&str
s - so the contenst of[&ToSql]
are double references. I don't see an easy way of achieving that without allocating. (let params: [&&str; 2] = params.iter().collect::<Vec<_>>().try_into().unwrap();
works and the allocation will likely be optimized out. Nighly or unsafe ways exist, see @ChayimFriedman's answer.)In this case, you can work around either by initially declaring:
by using an iterator, not an array:
In my case, I wasn't able to do anything like this because I was using execute, not query, and
execute_raw
exists only ontokio-postgres
, but not onpostgres
. So beware of these kinds of pitfalls.