This is probably a pretty open-ended question, but in all the Rust code I've been writing I've never needed to use the Box<T> type myself (I know it gets used in the standard library).
Is there a time when I should prefer heap allocation over the stack?
The only time I've ever needed Box for purely safe code is for owned trait objects, i.e. an owned version of &T where T is a trait. In those cases you need Box because it's the only way to own a trait object (or any unsized type). In my case I do wind up using it in places where I want to keep a pointer to an object for unsafe code and need to know that regardless of ownership the actual data doesn't move in memory.
atomic/lock-free operations where CPUs generally only support atomic operations on things that are pointer sized (or less),
for performance if T is large and is being moved around a lot, using a Box<T> instead will avoid doing big memcpys
The first one is generally handled by low-level libraries such as crossbeam (i.e. the APIs of such libraries will make the decisions Boxing or not, and you don't have to think, just follow their lead), and the second is reasonably rare: the cost of dynamic allocation and the (typically) poorer cache locality will mean Box<T> is usually slower than just T itself.
Thanks for explaining, I didn't want to feel like I was missing out on something
I'll have to find some profiling tools I can use to try and get a sense of what my Rust programs are actually doing at a point in time to understand why the options are there.
As my first real foray into a non-.NET language it still feels a bit magic.
If you know that you will allocate a lot, you might prefer avoiding allocating on the stack in order not to hit the stack limit and have a stack overflow. Note that Rust by default has a pretty big stack.
The simplest example on how somebody could hit this problem is when allocating buffers on the stack.
To give some context, in the issue I linked, the problem was that vagga uses musl which has 80 KB stack size instead of glibc's 8 MB.
Also, that stack overflow is still safe since Rust adds a guard at the end of the stack.