Summary
Add a Coerce
trait that will let create/update functions to also accept &Vec<T>
/&String
wherever &[T]
/&str
is expected.
Motivation
Ergonomics. We get rid of some (most?) of the as_slice()
calls. Users would be able to change code that looks like this string.push_str(another_string.as_slice())
to string.push_str(&another_string)
.
Detailed design
We add a Coerce
trait that we’ll let us “coerce” a &Vec<T>
into a &[T]
. The signature looks like this:
trait Coerce<P> {
fn coerce(self) -> P;
}
Then we can implement it on &Vec<T>
and &[T]
:
impl<'a, T> Coerce<&'a [T]> for &'a [T] {
fn coerce(self) -> &'a [T] {
self
}
}
impl<'a, T> Coerce<&'a [T]> for &'a Vec<T> {
fn coerce(self) -> &'a [T] {
self.as_slice()
}
}
Now we can change any function/method that expects a &[T]
to actually accept &Vec<T>
or &[T]
. As an example, the append method would become:
fn append<S: Coerce<&'a [T]>>(mut self, second: S) -> Vec<T> {
self.push_all(second.coerce());
self
}
This new append method would allow this:
let v1 = vec!(1u8, 2, 3);
let v2 = vec!(4u8, 5, 6);
let v3 = v1.append(&v2); // you can still use `v1.append(v2.as_slice())`
This treatment can also be applied to the String
/&str
pair.
Implementation “plan”
-
&Vec<T>
and&[T]
will implementCoerce<&[T]>
-
&String
and&str
will implementCoerce<&str>
- Update all the functions/methods in the standard library from accepting
&str
/&[T]
to acceptS
whereS: Coerce<&str>
/S: Coerce<&[T]>
.
This last step should break a minimal amount of code (I’m not 100% sure), because the updated functions would still accept &[T]
/&str
.
Drawbacks
- The signature of functions/methods become more complex.
Alternatives
Don’t do this, and use of the following alternatives:
- Implement the
Dereft
trait onVec
/String
: This let’s you do&*string
to get a&str
. This requires DST, and the core devs are not sure of whether they want to do this or not. -
Overloaded slice notation: This let’s you do
vector[:]
to get a&[T]
. AFAICT, the proposed signature requires DST to be implementable forVec<T>
andString
.
Advantages of this proposal over the alternatives
- Can be implemented right now.
- It doesn’t need a lang item nor DST.
- Shortest notation:
&string
vs&*string
vsstring[..]
vsstring.as_slice()
Ultimately if this doesn’t get implemented in the standard library, users can still implement this idea in their libraries.
Open questions
-
&mut Vec<T>
could implementCoerce<&'a mut [T]>
, but I’m not sure if that’s actually useful.
This just occurred to me in the morning, I figured I’d post it as a Pre-RFC to get feedback on the idea. I’m especially interested in hearing why do you think we should not do this.