I have a type DF { inner: DataFrame }
. I also have a type Header<'a>
that I can build from DataFrame
.
My thought was I could build a Header
by
- dereferencing
df
to point to my inner DataFrame
- call
into
specified in the From<DataFrame> for Header
trait to produce the header
value
This works using the following:
// where df: DF
let header: Header = (&*df).into();
Why doesn't it work using the following?
let header: Header = df.into()
impl Deref for DF
impl std::ops::Deref for DF {
type Target = DataFrame;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<&'a DataFrame> for Header<'a>
impl<'a> From<&'a DataFrame> for Header<'a> {
fn from(df: &'a DataFrame) -> Self {
Header::new(df.get_column_names())
}
}
What are the From
or Into
and potentially Deref
implementations you haven't mentioned?
Thank you for the follow-up. I updated the question to add those details.
Method resolution may be finding the blanket identity impl impl<T> From<T> for T { ... }
and generating an error, rather than continuing through method resolution to find the deref impl. I've had issues similar to that before, but it's hard to tell without the error message.
1 Like
The error when I run df.into()
is
The trait `From<DF>` is not implemented for `Header<'_>`
When I go ahead and implement From<&'a DF> for Header<'a>
I don't need to deref df, but still need to (&df).into()
. This seems like a "second" and redundant implementation. I'm happy to keep having to deref it manually in this particular scenario.
The benefit of Deref
seems to end with a single lookup. I can get to inner
but Rust won't type the inner value to lookup a trait from there?
Given obj: Ty
, method resolution looks for receivers of type
-
Ty
, &Ty
, or &mut Ty
-
*Ty
, &*Ty
, or &mut *Ty
- et cetera
So with df.into()
it first looks for a method into(self: DF)
, and it finds that DF
implements Into<T>
for some T
(if nothing else, itself) and stops the search.
You were wanting it to find into(self: &DataFrame)
, i.e. the &*Ty
case, and that's the first thing it looks for when you do (&*df).into()
.
Here's some alternatives:
// So you don't have to `(&*df).method()`
let header = Header::from(&*df);
impl DataFrame {
fn header(&self) -> Header<'_> {
Header::from(self)
}
}
// ...
let header = df.header();
The latter works because the method resolution mentioned above continues on until the &*Ty
case without finding any other header
methods for the preceding potential receiver types.
1 Like
The code samples were helpful. I like how you chose to define a header
method on DF
to create the header.
When defining methods for DF
(the parent), is there a convention in Rust to avoid depending on the DF
implementation of Deref
? (in which case I would use self.inner
instead of self
to access the inner DataFrame
)?