问号在类型参数绑定中意味着什么?

What does the question mark mean in a type parameter bound?

我找到了 std::borrow::BorrowMut 的定义:

pub trait BorrowMut<Borrowed>: Borrow<Borrowed>
where
    Borrowed: ?Sized,
{
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

Sized前面的问号在这个类型参数绑定(Borrowed: ?Sized)中是什么意思?

我咨询过:

但没有找到解释。请在您的回答中给出参考。


¹ 尤其参见 5.20 Traits 部分
² 和部分 6.1.9 Traits

表示该特征可选。当前语法在 DST syntax RFC.

中引入

据我所知,对 ? 有效的唯一特征是 Sized

在这个具体示例中,我们可以为 未确定大小的类型 实现 BorrowMut,例如 [T] — 请注意这里没有 &

一个内置实现利用了它:

impl<T> BorrowMut<[T]> for Vec<T>

:

This is a case of a widening bound; in general bounds impose more constraints, but in the case of Sized it was decided that unless otherwise noted a generic T would be assumed to be Sized. The way to note the opposite would be to mark it ?Sized ("maybe Sized").

这是一个基于示例的替代解释,可能有助于理解这个概念,Shepmaster 和 Matthieu 已经非常准确地解释了这个概念。

假设我们想要使用这样的通用实现来创建特征:

pub trait MyTrait<T> {
    fn say_hi(&self) -> String;
}

impl<T> MyTrait<T> for &T {
    fn say_hi(&self) -> String {
        return "Hi!".to_string();
    }
}

这将允许我们调用 say_hi() 对各种类型的引用,如下所示:

let a = &74;  // a reference to a SIZED integer
println!("a: {}", a.say_hi());
let b = &[1, 2, 3];  // a reference to a SIZED array
println!("b: {}", b.say_hi());

但是,如果我们这样声明一个函数:

fn be_fancy(arr: &[u16]) {
    println!("arr: {}", arr.say_hi());
}

,我们会得到一个编译错误:

error[E0599]: the method `say_hi` exists for reference `&[u16]`, but its trait bounds were not satisfied
   |
   |     println!("arr: {}", arr.say_hi());
   |                             ^^^^^^ method cannot be called on `&[u16]` due to unsatisfied trait bounds
   |
note: the following trait bounds were not satisfied because of the requirements of the implementation of `MyTrait<_>` for `_`:
      `[u16]: Sized`

可以看出,问题在于我们的特征仅针对 Sized 类型的引用实现。 Sized 是一种特殊的 marker 特性,默认情况下处于“开启”状态。在大多数情况下这很方便,但有时我们可能希望关闭该“限制”。 ?Sized 基本上是说“该类型可能会或可能不会调整大小”(与“未调整大小”不同)。

我们的函数 be_fancy 需要对 unknown(在编译时)大小的数组的引用。要解决这个问题,我们可以简单地将 T(相当于 T: Sized)替换为 T: ?Sized,如下所示:

pub trait MyTrait<T: ?Sized> {
    fn say_hi(&self) -> String;
}

impl<T: ?Sized> MyTrait<T> for &T {
    fn say_hi(&self) -> String {
        return "Hi yo!".to_string();
    }
}