Feeling Rust is so difficult

You have to use cloned and not clone like in @OptimisticPeach’s reply.
clone will try to clone the iterator while cloned will clone each element yielded by it.

3 Likes

Yes, expanding on @leudz’s post, it’s similar to saying the following:

iter.map(|x| x.clone())
//Same as
iter.cloned()

Or, with the recent stabilizations

iter.map(|x| *x)
//Same as
iter.copied()
2 Likes

Oh my, this is new info to me. I thought it was a typo at first. I have considered the clone approach before. However I hit a roadblock with that when Foo has an attribute that is a trait object. And it seems that trait object cannot be cloned

1 Like

The trait object cannot be cloned unless the trait object says so. But even then you cannot use Clone directly, or even a trait Foo: Clone because its signature is

fn clone(&self) -> Self

but Self is unsized, and therefore cannot be passed around like this function wants it to be.

So therefore you’d need a new trait that defines cloning a ?Sized object:

pub trait BoxClone: ?Sized + Clone {
    fn clone_boxed(&self) -> Box<Self>;
}

And implement it like so:

impl<T: Clone> BoxClone for T {
    fn clone_boxed(&self) -> Box<Self> {
        Box::new(self.clone())
    }
}

Really feels like something that can be done effortlessly in other language need a lot of work to achieve in rust

Perhaps in some cases, but the ability to explain things in more detail and not need to worry about certain things being “magic-ed away” by a garbage collector is a pretty important thing. And also, have you ever tried to write c/c++ code, I tried and it was a nightmare…

3 Likes

But I know a lot of places where it is the other way around, example: Iterate over an array, and sum all even digits

fn sum_even(a: &[u32]) -> u32 {
    a.iter().filter(|x| x % 2 == 0).sum()
}

easy pie. There are even more advances things which are so easy with iterators, it’s amazing. Image the amount of time you have to spend in C or C++. Manually iterating, making sure to not access it out of bounds. :sleepy:

:crab: is :heart:

3 Likes

Iterating over literals is simple enough. It’s iterating over objects that really confuses me. into_iter, iter, iter_mut… Wanting to return a vector of references, or actual objects. When you call foo.iter the foo is borrowed or not…and so on…

into_iter is a trait method from the IntoIterator trait. Use that, when you want to iterate over the values itself (instead of references). You have to give up ownership of course for that.

iter is like into_iter, but without giving up ownership and therefore you can only iterate over references of the values of your collection.

iter_mut is like iter, but lets you modify the values of the underlying iterator. You need mutable ownership/mutable reference of the underlying object of course.

What you actually want depends on your context. Fast and simple is into_iter. No allocation and no references, just pure object. iter when you need the object later on or just have a reference. iter_mut if you want to modify them. Easy as :cake:

2 Likes

Thank you for the detailed explanation. In Rust, is it recommended practice to work with reference always (not cloning) since this way there won’t be memory deallocation and allocation overheads. I have read some articles which recommends not to keep objects for too long and minimise context for which objects live so that ownership is easier to manage.

For example, i have a collection that needs to go through several calculations, filtering, mapping, logics and stuff. I can in theory just keep working using reference and mutating memory. Wonder if that is good practice (i am a functional programming enthusiast and cringe at the thought of mutation)

1 Like

I realize I’m taking you slightly out of context, but I feel this is at odds with

If you want the effortless feel of other languages, you need to at least adopt their way of modeling the problem. All those “other languages” are doing, most of the time, is making a sneaky clone while your back is turned. For example, most functional languages use some form of garbage collection, so the programmer doesn’t have to think about object lifetimes; if you want the same in Rust, it’s reasonable to use Rc, which can contain trait objects and is cheap to clone.

Just because Rust allows you to write super cool non-allocating zero-copy algorithms safely, doesn’t mean every algorithm you write should be super cool, zero-copy and non-allocating.

9 Likes

If you’re trying to do what you would do in a memory-managed language, you probably want to use Rc<dyn Trait> rather than Box<dyn Trait>; this most closely preserves the semantics of having multiple owned references that point to the same object. (and it always implements Clone)

Rc will forbid mutation; if you further need to mutate the object, use Rc<RefCell<dyn Trait>>.

2 Likes

Coming from FP, this bothered me to begin with too - let me paraphrase a quote I heard that finally made it click for me:

Most people will agree that the biggest source of confusion and bugs in software is shared mutable state.

Functional languages solve this by making the mutable stuff immutable. Rust solves this by making the mutable stuff not sharable. They’re both trying to solve the same problem, just in different ways :slight_smile:

22 Likes

Fortunately none of those operations (filtering, mapping, etc) would require mutation in rust, so you’re good there!

1 Like

Actually I do, cause it’s a collection of objects and I want to mutate the variables of the object

Okay, but that is a design choice (probably a good one) unrelated to the mapping, filtering and other operations that one does with iterators.

1 Like

Actually I do, cause it’s a collection of objects and I want to mutate the variables of the object

Getting to know the difference between mut and other types are very important in the beginning as this concept can be found in multiple places such as iter() and iter_mut() and into_iter(), as well as get() and get_mut(). One nice periodic table for rust types http://cosmic.mearie.org/2014/01/periodic-table-of-rust-types/

Having heard the mention of word object quite a few times, I would say that getting to think from a data point of view is very important in rust, which might be a bit different as compared to thinking from an object perspective. Rust Koans​​​​​ describes this nicely in story form.

1 Like

I’m afraid I am still not enlightened by the third story “puom” what is it trying to say???

I read it as a warning aimed at programmers who try to eliminate repetition in their code beyond the point of diminishing returns, making said code incomprehensible (like the monks’ words in the story).

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.