If your point was about explicit ownership being a little more tricky with self-referential structures, that's true, though the existence of std::collections::LinkedList shows that it's entirely possible to manage these structures and at least you still get the benefits of explicit ownership for the structure and the data within it.
I think the problem with this view is that Rust is not being used as a true programming language (like for implementing algorithms), but more as a "glue language".
If all the interesting stuff has to be done in libraries in "unsafe" mode, and all the uninteresting stuff (gluing) is done with borrow checking, then Rust is more a glue language. Which is fine. But don't call it a general purpose programming language.
Also, you seem to be suggesting that it's necessary to use unsafe code to implement these data structures in Rust. For something like the doubly-linked lists that were mentioned in an earlier comment, it usually suffices to use tools like Option and Rc for the links and to encapsulate the logic that manages those links inside functions like push_back and pop_back that you are surely defining to mutate your data structure anyway. Is there something specific you have in mind where this kind of strategy doesn't work and unsafe code is the only solution?
Trees are usually easy because each node has a single parent all the way up to the root and ownership can follow the same hierarchy. More general graphs are a little more tricky, but the same techniques that you can use to implement a specific case like a DLL generalise. For example, in Rust, you can combine Option and Rc to handle, respectively, the intermediate states while the structure is being manipulated and the shared ownership semantics.
You can do both in unsafe rust though. But you probably shouldn't no matter what high level non-GCd language you use.
/Another ex-cpp-master-race guy who has been impressed with Rust
However, if you're developing for embedded you'll probably want to be familiar with unsafe either way if you're going to use Rust.
Regarding self-referencing: Rust encourages you to design differently, which I've found leads to nicer and more thought out designs most of the time. Not all algorithms are possible (or efficient) without it though, and for those you'll have to use unsafe if you _really_ have to implement them yourself.
Specifically, the discussion about intrusive vs non-intrusive data structures and their frequency.
Though honestly, in C++ it is very rare I use something other than vector (potentially wrapped for specific use case, like boost flat_map)
(And yes, it's a niche data structure, vecs are far more common, but it's people's go-to "the borrow checker restricts you too much" example anyway.)
Seems a counter productive go-to argument given the amount of effort we (c++ coders) generally put in to avoiding non-adjacent memory access :)
FWIW I think the Rust community has done itself a disservice by focusing on the safety benefits. Const by default and move by default are much bigger deals in the day to day coding experience, but it’s hard to get across just how awesome they are.
That book looks great, thanks - should take me through a few corners I’ve yet to meet while keeping me entertained.
After 20 years of C++ and about the same number of hours of Rust, Rust makes me feel like Fire Mario because when I come to do a strict correctness and memory efficiency pass after writing something - it’s already correct. I suspect this will have a compound interest-like effect, similar to good code coverage empowering change.