I found the definition for std::borrow::BorrowMut
:
pub trait BorrowMut<Borrowed>: Borrow<Borrowed> where Borrowed: ?Sized, { fn borrow_mut(&mut self) -> &mut Borrowed; }
What does the question mark in front of Sized
mean in this type parameter bound (Borrowed: ?Sized
)?
I consulted:
but didn't find an explanation. Please give a reference in your answer.
In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).
Advertisements. The question mark (?), represents the wildcard, stands for unknown type in generics. There may be times when any object can be used when a method can be implemented using functionality provided in the Object class or When the code is independent of the type parameter.
It means that the trait is optional. The current syntax was introduced in the DST syntax RFC.
The only trait I am aware of that works for ?
is Sized
.
In this specific example, we can implement BorrowMut
for unsized types, like [T]
— note that there's no &
here!
One built-in implementation makes use of that:
impl<T> BorrowMut<[T]> for Vec<T>
As Matthieu M. adds:
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 genericT
would be assumed to beSized
. The way to note the opposite would be to mark it?Sized
("maybeSized
").
Here is an alternative explanation, based on an example, which might be helpful in understanding the concept, which was already explained very accurately by Shepmaster and Matthieu.
Let's say we want to make a trait with a generic implementation like this:
pub trait MyTrait<T> { fn say_hi(&self) -> String; } impl<T> MyTrait<T> for &T { fn say_hi(&self) -> String { return "Hi!".to_string(); } }
That will allow us to call say_hi()
on references to various types like this:
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());
However, if we declare a function like this:
fn be_fancy(arr: &[u16]) { println!("arr: {}", arr.say_hi()); }
, we will get a compiler error:
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`
As can be seen, the problem is our trait is only implemented for references to Sized
types. Sized
is a special marker trait that is "on" by default. In most cases that's convenient, but sometimes we might want to turn that "restriction" off. ?Sized
basically says "the type may or may not be Sized" (which is not the same as "unsized").
Our function be_fancy
expects a reference to an array of unknown (at compile time) size. To fix the problem, we can simply replace T
(which is equivalent to T: Sized
) with T: ?Sized
like this:
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(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With