为什么不能将 Box<dyn Trait> 传递给以 &mut Trait 作为参数的函数

Why can't Box<dyn Trait> be pased to a function with &mut Trait as parameter

我确定之前已经有人问过这个问题,但还没有遇到能准确描述此处情况的问题。我有以下代码:

let mut pool: Box<dyn redis::aio::ConnectionLike> = <...>
redis::cmd(COMMAND)
    .arg(LIST)
    .arg(value)
    .query_async(&mut pool)
    .await
    .unwrap();

这个returns错误:

error[E0277]: the trait bound `std::boxed::Box<dyn redis::aio::ConnectionLike>: redis::aio::ConnectionLike` is not satisfied
   --> svix-server/src/queue/redis.rs:66:30
    |
66  |                 .query_async(&mut pool)
    |                  ----------- ^^^^^^^^^ the trait `redis::aio::ConnectionLike` is not implemented for `std::boxed::Box<dyn redis::aio::ConnectionLike>`
    |                  |
    |                  required by a bound introduced by this call
    |

问题 1 -- 为什么错误提示未为 Box<dyn redis::aio::ConnectionLike> 实现特征?至少不应该说 &Box... 吗?

无论如何,如果我改为尝试将 pool.as_mut() 传递给 query_async,我会收到此错误:

error[E0277]: the size for values of type `dyn redis::aio::ConnectionLike` cannot be known at compilation time
   --> svix-server/src/queue/redis.rs:66:30
    |
66  |                 .query_async(pool.as_mut())
    |                  ----------- ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |                  |
    |                  required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `dyn redis::aio::ConnectionLike`

问题 2 -- 为什么这里需要 Sized? Rust 中的引用不总是 Sized 吗?

问题 3 -- 有什么方法可以将 dyn ConnectionLike 传递给这个

query_async方法,参考如下:

#[inline]
#[cfg(feature = "aio")]
pub async fn query_async<C, T: FromRedisValue>(&self, con: &mut C) -> RedisResult<T>
where
    C: crate::aio::ConnectionLike,
{
   ...
}

Why is Sized required here?

pub async fn query_async<C, T: FromRedisValue>(&self, con: &mut C) -> RedisResult<T>
where
    C: crate::aio::ConnectionLike,

Rust 中的所有类型参数都有一个隐式的 Sized 绑定,除非它们选择退出 — 编译器就像指定了 C: Sized 一样。

可能可以将此代码泛化为允许未确定大小的类型(写作 C: ?Sized);我不知道。

Isn't a reference in Rust always Sized?

是的,但隐式绑定在所指对象上,C

Is there any way to to pass a dyn ConnectionLike to this

您需要定义或使用现有类型,该类型实现了 ConnectionLike 特征并且 包含 dyn ConnectionLike,然后将可变引用传递给那种。

最干净的方法是使用 Box 本身,通过实现

impl<C: ?Sized> ConnectionLike for Box<C>
where
    C: ConnectionLike
{ ... }

但是,只有定义特征的箱子才能添加 impl

Question 1 -- Why does the error say the trait is not implemented for Box<dyn redis::aio::ConnectionLike>? Shouldn't it at least say &Box...?

不,因为引用不是泛型类型的一部分C。 Rust 不命名 entire 类型,它只命名两个类型不匹配的部分。该函数接受 &mut C 并且 C 是匹配的通用部分。 Box 类型是 C 的替代类型,它不实现此特征。

Question 2 -- Why is Sized required here? Isn't a reference in Rust always Sized?

引用确实是 Sized,但如上所述,我们正在将类型 &mut dyn redis::aio::ConnectionLike&mut C 进行匹配。这导致 Cdyn redis::aio::ConnectionLike

在 Rust 中,泛型类型默认有 Sized 绑定 你必须显式指定 ?Sized 绑定来放宽这个,作者这个功能没做。因此,C必须实现Sized,而dyn redis::aio::ConnectionLike则不需要。

Question 3 -- Is there any way to to pass a dyn ConnectionLike to this

可能,但不是直接的。您需要实现一种包装 reference-to-dyn ConnectionLikeBox<dyn ConnectionLike> 的类型,然后传递它。类似于:

struct BoxedConnectionLike(Box<dyn ConnectionLike>);

impl ConnectionLike for BoxedConnectionLike {
    // Implement proxy functions for the trait.
}