I've just been recently learning some Rust coming from a heavy C background. The dynamic trait objects mimic what I do in C with vtable pointers and glue functions, and then sometimes I look at it over and over to make sure the casts are right and I haven't forgotten a free or anything. The borrow checker and lifetimes mimic what I do in C with pointer constness and function documentation, and then often I get very nervous and look something up again and maybe add extra intermediary comments on the data flow within a function if I'm not absolutely sure I remembered what the lifetime behavior contract was for a caller or particular callee, and of course I have to do this with all the structs too. The Drop trait mimics what I do in C with either straight-line fallthrough-chained exit labels as interior-exit goto targets or carefully included cleanups before a lesser amount of interior returns, and then I sometimes have to convert between the two for readability, and in the former case I have to carefully use a temporary variable if I also needed to return a non-constant at the end of all that. Compound-value ownership movement mimics what I do in C with either structure assignment or memcpy, and if the latter, hope that I got the pointer types and type size right because memcpy won't check, and in either case hope that I was able to prove that the original structure wasn't going to be incorrectly reused and maybe memset it to zero just in case that makes something crash rather than cause memory corruption.
I expect I'll run into more friction once I get to any point where I want to make more dynamically interlinked data structures, though that might also push my designs into directions that use fewer pointers and more indexes or other indirect references to start with (I'm not sure of that yet)—and I really like the idea that if I can pare some of it down to a working “core” data structure semantic that involves pointer juggling, I can put carefully constructed hard-packed blocks of the pointer juggling in their own unsafe zone and then not be able to accidentally break the invariants outside of that.
Which, again, is almost exactly the same thing I'd tend to do in C with inline wrapper functions and visibility stuff, and making sure I compute all the intermediary results in one phase and putting all the hard mutations in a second, unfailable (except possibly for hard crashes due to null pointers or such) phase so that if something goes wrong the data doesn't wind up crashing down to a persistent broken state from mid-flight!
Heck, I've even done the newtype pattern (single-element structs for safe reinterpretation/bounding of an underlying type) in C before!
I've described the way I write C as “as though I were hand-cranking the front end of a strict, low-level Haskell or Caml compiler in my head”. Rust is the closest I've seen thus far to moving a big chunk of that part of me into the digital part of the compiler. So I'm guessing my taste wasn't exactly uncommon.