For a project I'm working on (an implementation of an obscure programming language), I have an enum Data, which represents data the interpreter is keeping track of (e.g., a variable). This language has infinite lists/lazy arrays, so I'm using a dyn Iterator for those. Since these lists can be stored in Data, and they themselves contain Data, it's a recursive data structure.
This works fine, until I need to clone some Data, which happens quite often. Currently, Data looks something like this:
pub enum Data {
Float(f64),
Int(BigInt),
String(String),
Array(Box<dyn Iterator<Item = Data>>)
}
And if I try to #[derive(Clone)] for it:
error[E0277]: the trait bound `dyn Iterator<Item = Data>: Clone` is not satisfied
--> src/shorispo.rs:28:11
|
23 | #[derive(Clone)]
| ----- in this derive macro expansion
...
28 | Array(Box<dyn Iterator<Item = Data>>)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `dyn Iterator<Item = Data>`
|
= note: required because of the requirements on the impl of `Clone` for `Box<dyn Iterator<Item = Data>>`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
I've tried dyn-clone, but this seems to create a sort of chicken-and-egg problem, since Data would need to be Clone.
Is there a way I can do this?
You have to implement Clone manually for your type. And to Clone a trait object requires some special sauce, which I derived from this answer.
// We have to provide a special trait for our clonable iterator,
// since Clone requires a Sized type (so we can't call it on a trait object).
trait CloneIterator: Iterator {
fn clone_box(&self) -> Box<dyn CloneIterator<Item = Self::Item>>;
}
// Implement our special trait for all Cloneable Iterators
impl<T> CloneIterator for T
where
T: 'static + Iterator + Clone,
{
fn clone_box(&self) -> Box<dyn CloneIterator<Item = Self::Item>> {
Box::new(self.clone())
}
}
// Use our special trait in Data instead
pub enum Data {
Float(f64),
Int(i64),
String(String),
Array(Box<dyn CloneIterator<Item = Data>>),
}
// Implement Clone manually, making use of `clone_box` for our special trait
impl Clone for Data {
fn clone(&self) -> Self {
match self {
Self::Float(f) => Self::Float(f.clone()),
Self::Int(i) => Self::Int(i.clone()),
Self::String(s) => Self::String(s.clone()),
Self::Array(b) => Self::Array(b.clone_box()),
}
}
}
playground
I found a way that works, using dyn-clone:
pub trait CloneIterator: DynClone + Iterator<Item = Data> {}
pub struct Array {
data: Box<dyn CloneIterator>
}
impl Iterator for Array {
type Item = Data;
fn next(&mut self) -> Option<Self::Item> {
self.data.next()
}
}
impl Clone for Array {
fn clone(&self) -> Self {
Array {
data: dyn_clone::clone_box(&*self.data)
}
}
}
#[derive(Clone)]
pub enum Data {
Float(f64),
Int(BigInt),
String(String),
Array(Array)
}
By making Array its own struct, I can make it Clone.
Related
I am implementing a double linked list in rust. I have created an iterator that works fine.
#[derive(Clone, Debug)]
pub struct LLCursor<T: Copy> {
pub cur: Option<Rc<RefCell<Node<T>>>>,
}
impl<T> IntoIterator for List<T>
where
T: Clone + Copy,
{
type Item = Rc<RefCell<Node<T>>>;
type IntoIter = LLCursor<T>;
fn into_iter(self) -> Self::IntoIter {
LLCursor {
cur: self.head.clone(),
}
}
}
impl<T> Iterator for LLCursor<T>
where
T: Copy,
{
type Item = Rc<RefCell<Node<T>>>;
fn next(&mut self) -> Option<Rc<RefCell<Node<T>>>> {
match self.cur.clone() {
Some(node) => {
self.cur = node.borrow().next.clone();
Some(node)
}
None => None,
}
}
}
I would like to make a function that can access the contents of the Nodes of the linked list as it is iterated over. Something like this:
pub fn print(self)
where
List<T>: IntoIterator,
<List<T> as IntoIterator>::Item: std::fmt::Debug,
{
for i in self {
println!("{:?}", Some(i.borrow().clone().item));
}
}
Error:
error[E0599]: no method named `borrow` found for associated type `<List<T> as IntoIterator>::Item` in the current scope
--> src/list.rs:90:51
|
90 | println!("{:?}", i.borrow().clone().item);
| ^^^^^^ method not found in `<List<T> as IntoIterator>::Item`
|
= help: items from traits can only be used if the trait is in scope
= note: the following trait is implemented but not in scope; perhaps add a `use` for it:
`use std::borrow::Borrow;`
I understand that i in this context is of type <List<T> as IntoIterator>::Item. I am new to rust so I do not see how it is useful that the iterator returns the associated type in this manner. I would expect i to be of type Option<Rc<RefCell<Node<T>>>>. Is there a way that I can pull this out of the associated type so I am able to access the elements of each individual Node?
None of the iterator code actually requires T: Copy, I suggest you remove it since it is obfuscating your problem. Then, since you know <List<T> as IntoIterator>::Item is actually T, you can use it directly:
pub fn print(self) where T: Debug {
for i in self {
println!("{:?}", i.borrow().item);
}
}
I also removed the .clone() when printing since its unnecessary and avoids the T: Clone constraint. See it working on the playground.
The reason for the error you got is because constraining that List<T>: IntoIterator and Item: Debug does not mean that Item is a Rc<RefCell<_>>. You would need an additional constraint T: Copy for it to deduce the correct IntoIterator implementation. No other implementations exist as far as your demonstrated code shows, but a non-conflicting implementation could in theory exist and the compiler does not make guesses.
As a side note, constraining on the Self type (here explicitly as List<T>) is pretty uncommon except in traits as you typically know what is needed for Self to satisfy those constraints, and its more descriptive to list that directly. (i.e. if Self needed to be Clone, but you know that Self is Clone if T is Clone, you would use T: Clone as the constraint).
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 existing AsArray 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.
}
In the following example, MyTrait extends IntoIterator but the compiler doesn't recognize it when used in a loop.
pub trait MyTrait: IntoIterator<Item = i32> {
fn foo(&self);
}
pub fn run<M: MyTrait>(my: &M) {
for a in my {
println!("{}", a);
}
}
I get the error:
error[E0277]: `&M` is not an iterator
--> src/lib.rs:6:14
|
6 | for a in my {
| ^^ `&M` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&M`
= note: required because of the requirements on the impl of `IntoIterator` for `&M`
= note: required by `into_iter`
Only M implements IntoIterator, but you're trying to iterate over a &M, which doesn't have to.
It's not clear what you hope to achieve with run, but removing the reference might be a start:
pub fn run<M: MyTrait>(my: M) {
for a in my {
println!("{}", a);
}
}
Note that M itself may be (or contain) a reference, so writing it in this way doesn't mean you can't use it with borrowed data. Here's one way to use run to iterate over a &Vec (playground):
impl<I> MyTrait for I
where
I: IntoIterator<Item = i32>,
{
fn foo(&self) {}
}
fn main() {
let v = vec![10, 12, 20];
run(v.iter().copied());
}
This uses .copied() to turn an Iterator<Item = &i32> to an Iterator<Item = i32>.
Related questions
Why is a borrowed range not an iterator, but the range is?
Am I incorrectly implementing IntoIterator for a reference or is this a Rust bug that should be reported?
How to implement Iterator and IntoIterator for a simple struct?
What is an idiomatic way to collect an iterator of &T into a collection of Ts?
How to properly pass Iterators to a function in Rust
Today I was playing around with function traits. Though the example I show below might not practically be very useful, I do wonder why it doesn't compile.
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
Here I implement a trait for a function type. This function type is generic over it's parameter. This means that if you were to do it like this:
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<F, A> Other for F where F: (Fn(A)) + 'static {
fn do_something_other(&self) {
do_something(self);
}
}
you get an error stating a type parameter is unconstrained.
I get this and don't believe it's possible to do it with generics. But the dynamic approach, why doesn't it work? It gives the following error:
I don't understand this error. It states I pass a Fn(A) -> (), which doesn't implement Other. However, this error occurs literally in the implementation of Other. How can it not be implemented here?
My first thought was because each closure is its own type. If it has to do with this, I find the error very weird.
The first construction fails because you cannot convert a &dyn A into a &dyn B, even when implementing B for dyn A.
trait A {}
trait B {
fn do_thing(&self);
}
impl B for dyn A {
fn do_thing(&self) {
let b: &dyn B = self;
}
}
error[E0308]: mismatched types
--> src/lib.rs:9:25
|
9 | let b: &dyn B = self;
| ------ ^^^^ expected trait `B`, found trait `A`
| |
| expected due to this
|
= note: expected reference `&dyn B`
found reference `&(dyn A + 'static)`
Well, you can convert traits but only with help from the source trait. But since in this case the source is Fn, that's not a route.
The second construction fails because Rust won't let you implement traits that can conflict. Trying to implement B for a type that implements A<_> will automatically be rejected because types can have multiple implementations of A<_>.
trait A<T> {}
trait B {
fn do_thing(&self);
}
impl<T, U> B for T where T: A<U> {
fn do_thing(&self) {}
}
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:7:9
|
7 | impl<T, U> B for T where T: A<U> {
| ^ unconstrained type parameter
Regarding Fns in particular, its somewhat hard to tell since usually function objects only implement a single Fn trait. However, the keyword is usually since you can enable a feature on nightly to do just that. And the trait system usually doesn't play favorites.
So what can you do? Well the first method is still functional, just you have to keep the implementation within the trait. You can use the second method if you use a concrete types for the function arguments.
You can conceivably implement Other for &dyn Fn(_) (implementing it on the reference and not the object itself). But that's not particularly convenient with how Fn objects are usually used.
pub fn do_something(o: &dyn Other) {}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for &dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
fn main() {
// THIS WORKS
let closure: &dyn Fn(_) = &|x: i32| println!("x: {}", x);
closure.do_something_other();
// THIS DOESN'T WORK
// let closure = |x: i32| println!("x: {}", x);
// closure.do_something_other();
}
Another option would be to make the Other trait generic in order to constrain A, but that of course depends on how its designed to be used.
I have a trait in which I want to provide a method. The method is to be implemented in terms of some helpers that have no business being inside the trait and are non-trivial enough that dynamic polymorphism makes more sense than making them generic. So I have code along the lines of
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self);
}
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
Which, however, does not compile, with error:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> <anon>:9:19
|
9 | use_trait(self);
| ^^^^ the trait `std::marker::Sized` is not implemented for `Self`
|
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `Trait`
I understand why—it is not guaranteed somebody won't implement the trait for an unsized type (converting from &T where T: Trait to &Trait requires T: Sized, but the declaration does not require that).
However, the advice will not do what I need. I can add
fn needed(&self) -> &str where Self: Sized
but then the needed() method won't be accessible on &Trait (because Trait : ?Sized), which renders the thing useless, because the type (the actual one that does something useful) is always handled as Arc<Trait>. And adding
trait Trait: Sized
is even worse, because that does not permit &Trait at all (Trait as a type is unsized, so Trait type does not implement trait Trait).
Of course I can simply make
fn use_trait<T: Trait>(x: &T)
but there is a lot behind it in the real code, so I don't want monomorphisation there especially since the trait is otherwise always handled as trait object.
Is there any way to tell Rust that all types that impl Trait must be sized and here is a definition of a method that should work for all of them?
You need an additional as_trait function on Trait and its implementations:
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self.as_trait());
}
fn as_trait(&self) -> &Trait;
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn as_trait(&self) -> &Trait {
self as &Trait
}
}
You can try it on the playground. (trait objects)
Enhanced version of #JoshuaEntrekin's answer:
The helper as_trait function can be put in an auxiliary trait that gets blanket implementation for all Sized types trying to implement Trait. Then the implementer of Trait does not have to do anything special and the conversion works.
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait : AsTrait {
fn needed(&self) -> &str;
fn provided(&self) where Self : AsTrait {
use_trait(self.as_trait());
}
}
trait AsTrait {
fn as_trait(&self) -> &Trait;
}
impl<T : Trait + Sized> AsTrait for T {
fn as_trait(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
(on play).
It would also be possible to simply put provided in the auxiliary trait, but then it would have to dynamically dispatch to the other methods of Self unnecessarily.
Update: Actually, the point is that it should still be possible to override provided.
Now the above can be improved further by making it generic. There is std::makrer::Unsize, which is unstable at the time of this writing. We can't make
trait Trait : Unsize<Trait>
because Rust does not allow CRTP, but fortunately it is enough to put the constraint on the method. So
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) where Self: AsObj<Trait> {
use_trait(self.as_obj());
}
}
trait AsObj<Tr: ?Sized> {
fn as_obj(&self) -> &Trait;
}
// For &'a Type for Sized Type
impl<Type: Trait> AsObj<Trait> for Type {
fn as_obj(&self) -> &Trait { self }
}
// For trait objects
impl AsObj<Trait> for Trait {
fn as_obj(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn provided(&self) {
println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty.
}
}
fn main() {
let s: &Trait = &Struct();
s.provided();
}
(on play)
This finally makes it transparent for the implementors of other versions.
See also this users thread.