We have to be careful with the words "ownership" and "owner" in Rust world.
In Rust "ownership" has a specific meaning. The owner of a piece of data is the one responsible for destroying (deallocate/delete/free) the data when it is no longer required. There can only be one owner. Ownership can me "moved" to some other owner but there is always only one. This must be so otherwise we would end up with multiple users of data thinking they should free it, or none. Confusion would reign as it often does in languages like C, C++. Resulting in multiple freeing the same data, use of freed data or memory leaks.
Everyone else is a "borrower", accessing the data through mutable or immutable references.
In the world of interpreted languages none of the code you write "owns" the data in that way, the interpreter does. The interpreter will decide to destroy things when it notices there are no more users of the data.
What one has with interpreted languages is multiple references to data.The same effect can be achieved in Rust by using smart pointers, like Rc
or Arc
. Dictionaries and arrays in such languages map to Vectors, HasMaps and other containers in Rust.
My impression is that the only thing Rust is lacking (at least with any convenience) from Object Oriented Programming is inheritance. However those into OOP now a days chant "Favour composition of inheritance". A notion that comes from the famous "Gang of Four" book on patterns. Inheritance is increasingly seen as an anti-pattern by many. So Rust is not missing anything of importance there.
I find it hard to think of that "standard" architecture you speak of. Something that is applicable to the widest range of tasks. There is so much variability in tasks.
Your mention of "adapters" immediately brings to mind Rust's traits. Traits can be thought of as interfaces. There can be many implementations of an interface. They an be swapped in and out of the "core" logic as required.
Your mention of "dependencies (UI -> Core; Adapters -> Core)." brings to mind my favourite way to think about problems. A collection of black boxes, each dedicated to a single , well defined, task. Communicating to each other via channels. std::sync::mpsc - Rust
Which is how my first production code in Rust has been put together. When using an async run time like Tokio and it's channel mechanisms this does not even consume expensive real threads.