You manually manage memory via ownership rules and lifetimes.
You can allocate memory for a Vec with Vec::new. Dropping it deallocates. When and where it's dropped is important. Passing ownership around is important. These are parts of managing the memory.
If you need something to be on the heap, you use Box. If you need something to be shared, you use something like Arc or Rc.
Rust makes it nice to implicitly handle the common cases so you don't feel like you're doing manual memory management, but you're making decisions about that memory management at every step of the way.
To add to this, Java and other GC languages in some sense have manual memory management too, no matter how much we like to pretend otherwise.
It's easy to fall into a trap where your Banana class becomes a GorillaHoldingTheBananaAndTheEntireJungle class(to borrow a phrase from Joe Armstrong), and nothing ever gets freed because everything is always referenced by something else.
Not to mention the dark arts of avoiding long GC pauses etc.
It's possible to do this in rust too, I suppose. The clearest difference is that in rust these things are explicit rather than implicit. To do this in rust you'd have to use 'static, etc. The other distinction is compile-time versus runtime, of course.
> The clearest difference is that in rust these things are explicit rather than implicit. To do this in rust you'd have to use 'static, etc.
You could use 'static, or you can move (partial) ownership of an object into itself with Rc/Arc and locking, causing the underlying counter to never return to 0. It's still very possible to accidentally hold on to a forest.
> It's easy to fall into a trap where your Banana class becomes a GorillaHoldingTheBananaAndTheEntireJungle class(to borrow a phrase from Joe Armstrong), and nothing ever gets freed because everything is always referenced by something else.
Can you elaborate on this? I'm struggling to picture a situation in which I have a gorilla I'm currently using, but keeping the banana it's holding and the jungle it's in alive is a bad thing.
The joke is you're using the banana but you didn't actually want the gorilla, much less the whole jungle. E.g. you might have an object that represents the single database row you're doing something with, but it's keeping alive a big result set and a connection handle and a transaction. The same thing happening with just an in-memory datastructure (e.g. you computed some big tree structure to compute the result you need) is less bad, but it can still impact your memory usage quite a lot.
To extend upon this, memory generally has a single owner. When it goes out of scope, it gets freed [1]. The drop() function, which appears analogous to free() in C/C++, is actually just an empty function who's sole purpose is to take ownership and make it go out of scope, which immediately frees the memory [2].
> This function is not magic; it is literally defined as: pub fn drop<T>(_x: T) {}
This is usually more deterministic than GC languages (no random pauses), but can be less efficient for highly nested data structures. It also makes linked lists impossible without using "unsafe rust", as it doesn't abide by the normal ownership rules.
Linked lists to arbitrary memory, yes. Linked list from a consecutive chunk of memory managed by a bump allocator: just as easy as any language, no need for unsafe.
Admittedly not the easiest language to make a linked list in.
The way I sometimes describe it is that memory is essentially managed at compile time in Rust, whereas with a (tracing) GC it happens at runtime, and in C it's done manually by the programmer. This is a simplification, but it's both true that Rust is similar to C in that there isn't a runtime cost to memory managed and that it's similar to Java in that outside of specific APIs, you have strong guarantees about certain issues with memory not being possible because they're automatically handled by the language.
I half-heartedly tried to make "static memory management" (Rust/C++ RAII) vs "dynamic memory management" (GCs or Rc/Arc in Rust/C++) happen but people generally didn't like it. I do think it's a good framing though.
Yes, by deciding on when, where and how you pass it. You know when it is created and destroyed because you wrote the code that either does that directly, or follows the convention (destroy when out of scope, or use of arc - it is programmer's decision).