Reputation: 11
I have a question about Rust traits. I have the following:
pub trait SelectAsDsl: Sized {
type Output;
fn select_as<SQ>(self, subquery: SQ, alias: String) -> Self
where
SQ: AsExpression<SQ> + SingleValue + SqlType;
}
#[derive(QueryId, Debug, Clone)]
pub struct SelectAs<SQ> {
subquery: SQ,
alias: String,
}
impl<T> SelectAsDsl for SelectAs<T> {
type Output = Self;
fn select_as<SQ>(self, subquery: SQ, alias: String) -> Self
where
SQ: AsExpression<SQ> + SingleValue,
{
SelectAs {
subquery,
alias,
..self
}
}
}
This gives an error "expected type parameter T
, found type parameter SQ
" in the trait implementation when returning the struct, but when naming them the same, the compiler complains that the name is already in use.
When changing it to create a void struct and returning self, the compiler gives no error.
impl<T> SelectAsDsl for SelectAs<T> {
type Output = Self;
fn select_as<SQ>(self, subquery: SQ, alias: String) -> Self
where
SQ: AsExpression<SQ> + SingleValue,
{
let _ = SelectAs { subquery, alias };
self
}
}
How is this caused and how should I fix this?
Upvotes: 1
Views: 547
Reputation: 71440
There is no connection between the struct's SQ
and the trait method's SQ
(except they share the same name, of course). The fact that they share the same name is just confusing. select_as()
should return Self
, which is SelectAs<T>
in the context of the impl
you showed, but it returns SelectAs<SQ>
.
The fix is obviously to make it returning SelectAs<T>
. Since it needs subquery
to be of type T
, that means we need to declare it so. This is a bit problematic since the trait (where we declare it) does not have access to T
. So we should declare T
(or SQ
) as a parameter of the trait instead of the method (maybe even an associated type):
pub trait SelectAsDsl<T>: Sized {
type Output;
fn select_as<T>(self, subquery: T, alias: String) -> Self
where T: AsExpression<T> + SingleValue + SqlType;
}
impl<T> SelectAsDsl<T> for SelectAs<T>
{
type Output = Self;
fn select_as(self, subquery: T, alias: String) -> Self
where T: AsExpression<T> + SingleValue + SqlType
{
SelectAs {
subquery,
alias,
..self
}
}
}
Upvotes: 1