I have a type that looks like this:
#[derive(Debug, Copy, Clone)]
pub enum Block<'a> {
// ...
}
It implements both Copy
and Clone
because all it holds inside is references.
What I now want to add is this:
#[derive(Debug, Clone)]
pub enum OwnedBlock {
// ...
}
impl<'a> ToOwned for Block<'a> {
type Owned = OwnedBlock;
fn to_owned(&self) -> Self::Owned {
OwnedBlock::from_block(*self)
}
}
Block
here is like a str
and OwnedBlock
is like String
.
But turns out alloc
already provides an impl that conflicts with this:
error[E0119]: conflicting implementations of trait `alloc::borrow::ToOwned` for type `block::Block<'_>`
--> src/block.rs:472:1
|
472 | impl<'a> ToOwned for Block<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `alloc`:
- impl<T> alloc::borrow::ToOwned for T
where T: core::clone::Clone;
I understand why the default impl might seem to be useful, but it isn't for me here.
I'm okay with usage of nightly-only features.
There's no direct way around the blanket implementation, but even if there was, you presumably can't meet the associated type requirement either:
impl<'a> Borrow<Block<'a>> for OwnedBlock {
// The signature approximately requires you to own the `Block<'_>`,
// e.g. in a field.
fn borrow(&self) -> &Block<'a> { ... }
}
You can perhaps work around both with enough indirection...
...though I don't know if it's worth it.
impl From<Block<'_>> for OwnedBlock
is an alternative.
1 Like
Yeah, does standard library have a special case for built-in types? If that is the case, then there might be a chance to get the same functionality for custom types at some point.
There's no special casing going on for std
here. The uncovered blanket implementation is for Sized
T
, and all the other std
implementations are for unsized types like str
. There's no overlap because Sized
is a fundamental trait -- you implement it from day one or it is a breaking change to implement it -- so the coherence checker can assume str
, etc, will never implementat Sized
.
(Clone
requires Sized
to boot, but Clone
itself is not fundamental.)
If you had a struct
and not an enum
, a custom unsized type might have been another way forward (although they have their own drawbacks too).
The dyn
workaround is itself a custom unsized type in some sense, I suppose.
1 Like
I see, Sized
is the key piece here, which str
doesn't implement
1 Like