简体   繁体   中英

`AsArray` cannot be made into an object when implementing a trait for a trait

Basically I'm trying to make a trait that indicates the ability to be converted into a 2D ndarray aka ndarray::Array2 :

trait Into2DArray{
    fn to_array(&self) -> Array2<f64>;
}

I would like to do this by expanding the existingAsArray trait, but Rust forbids me from implementing a third party trait for a third party struct ( polars::DataFrame ) for some esoteric reason, so instead I have to make my own trait for this.

Anyway, this works well for polars::DataFrame :

impl Into2DArray for DataFrame {
    fn to_array(&self) -> Array2<f64> {
        return self.to_array();
    }
}

However, I also want to implement this for anything that is already convertable into a 2D array, so I implement this trait for the AsArray trait mentioned above:

impl Into2DArray for AsArray<'_, f64, Ix2> {
    fn to_array(&self) -> Array2<f64> {
        return self.into();
    }
}

However the compiler gives me grief for this:

   |
26 | impl Into2DArray for AsArray<'_, f64, Ix2> {
   |                      ^^^^^^^^^^^^^^^^^^^^^ `AsArray` cannot be made into an object
   |
   = note: the trait cannot be made into an object because it requires `Self: Sized`
   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>

I understand that has something to do with object safety but I thought I had fulfilled all the criteria mentioned on that page, namely the trait doesn't return Self , and all the generic parameters of AsArray are specified.

What is going wrong, and how can I fix it?

What you were trying to do is implementing the Into2DArray trait for the AsArray dynamic trait object. There should have been a warning of using AsArray without dyn anyway.

But this is not what you actually want. You want to implement it for any type that implements AsArray . Just like you did in your comment.

It is important to know the difference between these two things:

trait NeedThis {
    fn can_be_called_by_the_impl(&self) {}
}

trait ToDoThis {
    fn example(&self);
}

impl ToDoThis for dyn NeedThis {
    fn example(&self) {
        self.can_be_called_by_the_impl()
    }
}

impl NeedThis for u8 {}

fn main() {
    let num: u8 = 0;
    // num.example(); // doesn't work because ToDoThis is not implemented for u8

    let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
    num_as_trait_obj.example(); // works because this time it is a trait object
}
trait NeedThis {
    fn can_be_called_by_the_impl(&self) {}
}

trait ToDoThis {
    fn example(&self);
}

// removing ?Sized would make it the same as T: NeedThis + Sized
impl<T: NeedThis + ?Sized> ToDoThis for T {
    fn example(&self) {
        self.can_be_called_by_the_impl()
    }
}

impl NeedThis for u8 {}

fn main() {
    let num: u8 = 0_u8;
    num.example(); // works because we implemented it for all types that implement NeedThis

    let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
    num_as_trait_obj.example(); // works because dyn NeedThis also implements NeedThis.
    // This is only true because we added ?Sized to the bounds of the impl block.
    // Otherwise it doesn't work because dyn NeedThis is not actually Sized.
    // And a Sized bound is implied by default.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM