Что означает вопросительный знак в привязке параметра типа?

Я нашел определение для std::borrow::BorrowMut:

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

Что означает знак вопроса передSizedзначит в этом типе параметр привязан (Borrowed: ?Sized)?

Я консультировался:

но не нашел объяснения. Пожалуйста, дайте ссылку в вашем ответе.


¹особенно смотри раздел 5.20 Черты
²и раздел 6.1.9 Черты

2 ответа

Решение

Это означает, что черта является необязательной. Текущий синтаксис был введен в синтаксис DST RFC.

Единственная черта, которую я знаю, это работает для ? является Sized,

В этом конкретном примере мы можем реализовать BorrowMut для нестандартных типов, таких как [T] - обратите внимание, что нет & Вот!

Одна встроенная реализация использует это:

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

Как добавляет Матье М.:

Это случай расширения границы; в общем случае ограничения накладывают больше ограничений, но в случае Sized было решено, что если не указано иное T будет считаться Sized, Чтобы отметить обратное, нужно отметить это ?Sized ("может быть Sized").

Вот альтернативное объяснение, основанное на примере, который может быть полезен для понимания концепции, которая уже была очень точно объяснена Шепмастером и Матье.

Допустим, мы хотим создать трейт с такой общей реализацией:

      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в основном говорится, что «тип может быть или не иметь размера» (что не то же самое, что «неразмерный»).

Наша функция be_fancyожидает ссылку на массив неизвестного (во время компиляции) размера. Чтобы решить проблему, мы можем просто заменить 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();
    }
}
Другие вопросы по тегам