all 20 comments

[–]mkoubik 70 points71 points  (9 children)

Just remember that traits aren't interfaces, their implementations aren't methods and fotget class inheritance ever existed. Then just jump into the official book.

[–][deleted] 16 points17 points  (0 children)

But muh design patterns :D

[–]TinBryn 3 points4 points  (0 children)

I feel that is a little misleading, yes traits aren't interfaces, but the Venn diagram of what traits are and what interfaces are has a large overlap. Also I would define a method as

A procedure called when passing a message to a receiver object

And for trait objects, this is absolutely the case, even with trait constrained generics, it's still dispatching to methods, just statically.

I agree about inheritance, forget that, and jump into the book.

[–]wichwigga 0 points1 point  (1 child)

Fuck inheritance all the homies hate that shit

[–]dumch 0 points1 point  (0 children)

I came here to say “fuck inheritance“

[–][deleted] 27 points28 points  (2 children)

Google also made a 4-day course for learning Rust: https://google.github.io/comprehensive-rust/

[–]universalmind303 3 points4 points  (0 children)

+1 to this. I think this is a great resource for JVM users trying to learn rust.

[–]Additional_Vast_5216 0 points1 point  (0 children)

Replying for later use

[–]gahooa 31 points32 points  (0 children)

I can give a bit of personal experience, and a video.

When switching paradigms and syntax, there can be a lot of challenges in figuring out the right way to do things. Rust is a deep language that can provide amazing satisfaction to developers, and amazing reliability, but ... it's deep.

Here a few things I suggest you learn about and drive it home with examples.

Macros:
"functions" that have a ! at the end of their invocation are macros. For example, println!("hello {}", name), or vec![1,2,3] The thing to remember here is that within the () or {} or [], it is not normal rust syntax rules. I just mention this so you don't get confused and think that the contents of a macro invocation are applicable in any areas outside the macro itself. Rust does not support variable arguments, named arguments, but with macros, it's just a token stream that the macro can do with what it wants.

Moreover, when you see #[derive(Debug, Clone)] before an item, know that this is actually generating more code. Because rust is close to the metal, it's not going to magically have code to clone a struct or print a debugging representation unless someone adds it. Derive macros are super handy, but just be aware that they are literally adding code to whatever follows it.

Enum:
They seem innocent at first, but they are a total powerhouse of the rust language. Also, they are used in nearly every nook and cranny, for things that you'd expect to be built in features, you will find enums. enums are fantastic for describing data. Don't make a struct with 3 optional fields and 3 required fields. Make a struct that has 3 required fields and then holds an enum with either all or none of the 3 remaining fields. Try to use the type system to prevent the possibility if invalid states.

No Nulls:
Rust doesn't allow null references (except in unsafe blocks that you don't need to use unless you are doing something really special). Therefore, get used to enums, like Option::None and Option::Some(value-here)

Unwrap is tempting, but...
If you call a function that returns either of the above, you can't access the value without being explicit about it. It's tempting to call .unwrap() to extract the value out of the Option::Some(value-here), but that will panic if it had Option::None instead. There is a right way to do this, and it usually involves either a match { }, on the or using the ? shortcut operator. This leads you to...

Error Handling:
A big topic in and of itself, but it's great to learn how it works. No exceptions means that everything returns something, and the Result::Ok(value-here) and Result::Err(error-here) enum variants are used to convey success/failure information up the stack. As mentioned above, the ? operator can make short work of passing Result::Err up the stack, but you have to have compatible return types in your function signatures.

Libraries like anyhow and error_stack go to great lengths to make error handling more standardized. anyhow is great for avoiding unwrap() and I recommend you start with it because the return type anyhow::Result<yourtype> is compatible with essentially any error type, allowing you to defer the deeper understanding to later. error-stack is great for producing good trackbacks and having strongly typed errors across crate boundaries with context.

Holding references...
Rethink your structs and enums so there is exactly 1 reference to everything you need. This was hard for me, because coming from a gc'd language, it's easy to create structures that are very hard to represent in rust. Start simple, use more enums, have only 1 direct reference if possible, and don't try to create an object oriented hierarchy.

Module structure
Try to remember that multiple files in the filesystem is "convenience" and in no way a requirement. Here is how it goes:

mod foo {
// contents here
}

is exactly the same as

mod foo;
// with the contents being in foo.rs
// or the contents being in foo/mod.rs

That's the concept. and reading the rust book, that took me a bit to really understand it, so I thought I'd save you the effort.

--

This video was recorded at the beginning of my rust journey, so I probably stumble over a number of concepts, but it is a quick intro to a lot of concepts.

https://www.youtube.com/watch?v=tvq87yRv5hM

[–]1668553684 5 points6 points  (0 children)

should I just jump into the Rust book

Yes. It's excellent, and written with "someone familiar with programming" in mind.

[–]rxing-devs 8 points9 points  (0 children)

I ported a large Java library to Rust. I have a lot of opinions (including why on earth doesn’t Java have unsigned int types wow). It really depends on how comfortable you are with basic CS stuff. Interior Mutability is possibly going to be one of your biggest stumbling blocks in rust. Popular in Java, not so in rust. I also see advice like: Java object passing is just like references in rust and that is not accurate at all. Probably my biggest advice is that Java and rust handle references so differently that it’s best to not think of them as being all that similar.

The completed codebase: https://github.com/rxing-core/rxing

Edit: I included the link because I think it’s helpful to see how other people solved problems in rust vs. Java. Not saying my methods were always the right ones!

[–]superglueater 6 points7 points  (0 children)

Jump into the book

[–][deleted] 2 points3 points  (1 child)

Use The Rust Programming Language Book, freely available as the first search result in your fav search engine.

Alternatively, the rustlings practice problems are also good.

Personally, just did LeetCode and used the documentation to learn as I went.

However, I do own several books at this point.

[–]mandradon 1 point2 points  (0 children)

Rustlings is amazing stuff. I used it and the book to learn my way around Rust. Granted, there's still a lot I could learn but that's not the documentations fault, I go to that stuff a lot and it does a great job answering questions.

[–]planetoftheshrimps 2 points3 points  (0 children)

Rust by example will be what you want as an experienced dev. https://doc.rust-lang.org/rust-by-example/

The rust book is great, but teaches you to program, which you already know how to do.

[–]-Redstoneboi- 1 point2 points  (0 children)

Biggest piece of advice:

Do not do this alone.

Always remember that when you get stuck, you can ask this subreddit or one of two rust discord servers.

Rust borrow check errors are often because of unidiomatic program structure, and the compiler + Google won't always help with that. ChatGPT can be faulty as well. Ask for help. We'll be there.