Reputation: 480
I'm implementing tuple flattening for Rust. It requires converting
((A,B), (C, (D, E)), F)
into
Cons[
Cons[A, B, Nil],
Cons[
C, Cons[D, E, Nil], Nil
],
F,
Nil
]
I tried using specialization, but the compiler doesn't like it:
/// For non-tuple types.
impl<T> IntoCons for Val<T> {
default type Out = Cons<T, Nil>;
default fn into_cons(self) -> Cons<T, Nil> {
Cons {
head: self,
tail: Nil,
}
}
}
How can I do this? Any alternative that doesn't use unsafe
is ok.
Complete example:
#![feature(specialization)]
use std::fmt::{Debug, Display};
pub trait Tr {
type It;
fn it(self) -> Self::It;
}
impl<T> Tr for T
where
T: Debug,
{
default type It = u8;
default fn it(self) -> Self::It {
0
}
}
impl<T> Tr for T
where
T: Debug + Display,
{
type It = u16;
fn it(self) -> Self::It {
0
}
}
fn main() {}
Compiler output:
error[E0308]: mismatched types
--> src/main.rs:17:9
|
16 | default fn it(self) -> Self::It {
| -------- expected `<T as Tr>::It` because of return type
17 | 0
| ^ expected associated type, found integral variable
|
= note: expected type `<T as Tr>::It`
found type `{integer}`
Upvotes: 2
Views: 727
Reputation: 1980
The problem here is that you are returning Self::It
but give it a 0. What happens if someone were to implement this with It
being String
? Since there is no way to prove that this is always going to be a number, you either need a trait bound or to change the method signature.
A possible way of doing it is like this:
pub trait Tr {
type It: Default;
fn it(self) -> Self::It;
}
impl<T> Tr for T
where
T: Debug,
{
default type It = u8;
default fn it(self) -> Self::It {
Default::default()
}
}
Upvotes: 2