Что означает вопросительный знак в привязке параметра типа?
Я нашел определение для std::borrow::BorrowMut
:
pub trait BorrowMut<Borrowed>: Borrow<Borrowed>
where
Borrowed: ?Sized,
{
fn borrow_mut(&mut self) -> &mut Borrowed;
}
Что означает знак вопроса передSized
значит в этом типе параметр привязан (Borrowed: ?Sized
)?
Я консультировался:
- Язык программирования Rust ust книга,
- The Rust Reference², а также
- Что значит "Размер не реализован"? на переполнение стека
но не нашел объяснения. Пожалуйста, дайте ссылку в вашем ответе.
¹особенно смотри раздел 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();
}
}