8 deadly mistakes beginner Rust developers make

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up bro stations my name is Bogdan and in today's video I'm going to cover eight common mistakes new rust developers make also at the end of the video I'm going to cover a bonus mistake that even more experienced rust developers make so stick around for that this video is based on a great blog post written by Michael Bryan and I'll provide a link to it in the description speaking of useful things to read if you haven't already make sure to get your free rust cheat sheet by heading over to let's get rusty.com forward slash cheat sheet now let's jump into the video the first mistake new rust stations make is unnecessary in Direction in this example we have a function called Fancy print which takes a string as input and prints it out a new rust station May notice that fancy print does not need to mutate its input and update the input type to be a reference to an own string this works however it introduces unnecessary indirection an own string can be automatically coerced to a string slice so changing s to a string slice still works and it has the extra benefit of making the API more flexible because fancy print can now accept references to own strings or string slices the second mistake new restations make is overusing slice indexing indexing into a slice or array is very common in other languages such as C however it's very easy to crash your program with an index out of bounds error using this approach luckily we can avoid these problems in Rust in this example we are calculating the difference between adjacent elements in a vector and must remember to start the for loop at index 1 not 0. instead of indexing into the vector we can use the array Windows method to access adjacent elements we can improve this further by getting rid of the for Loop and using the map method instead as you can see rust's powerful type system enables us to safely perform operations on vectors arrays and slices the third mistake new rust stations make is using Sentinel values Sentinel values are values that have a special meaning examples include negative 1 and empty string and null here is a code example in C the find function takes an array the array's length and a value to find as inputs negative one is returned if the value could not be found in Rust we don't need to use sentinel values because the type system gives us a way to represent optional values in this rust code example get username returns an empty string if ID is not equal to 1. instead we can return the option enum by updating the function signature we are making it clear to the color that this function might return none and that case should be handled speaking of enums the fourth mistake nuvra stations make is not taking advantage of them in this example a user's role is represented as a string this is bad for all kinds of reasons the role can be mistyped for example also it's not easy to tell when roles are added or removed instead using an enum would be the right approach in this case here we've defined an enum named role inside cam published blog we use a match expression to return the correct Boolean value match expressions and pattern matching in general are very powerful when used on edoms however another mistake new rust stations make is not utilizing pattern matching enough in this example an optional type is being checked to be the sum variant and then unwrapped and in this example an array is checked to see if it's not empty before retrieving the first element both of these examples can be improved by using pattern matching specifically the iflet syntax the fifth mistake neurostations make is not doing error handling properly error handling in Rust is a complex topic that warrants its own video but I want to highlight two common mistakes the first mistake is not using the question mark operator for error propagation in this example we have a function called parse then add inside the function body we parse two strings slices as integers check for parsing errors and if there are none return the sum this code works but can be improved using the question mark operator to propagate errors we can shrink this function down to just a few lines of code another mistake new restations make is creating custom error types that don't implement the error trait implementing the error trait has a few benefits it semantically marks your type as an error it gives your type the basic components of a good error in Rust and it allows your type to work with the rest of the rust error ecosystem specifically third-party crates however implementing the errored trait manually is tedious and involves boilerplate that can clutter your code instead you should use the this error library to implement the necessary traits via macros the sixth mistake neurostations make is not using trades provided in the standard Library let's go through a few useful ones the default tray allows you to provide useful fault values for your types in this example we have a struct called player instead of manually initializing level items and special power every time we construct a new player instance let's implement the default trait now we are able to construct new player instances by calling the default Associated function also note that the default trait can be derived if all the structs fields also Implement default another set of useful trades is from and try from these traits allow you to convert between types and are especially useful for converting between errors the only difference between these trades is that trifrom is used for conversions that can potentially fail while from is used for conversions that must not fail in this example we've defined a custom error type called CLI error it has two variants i o error and parse error then we implement the from trade twice one implementation to convert an i o error to a CLI error and the other to convert a parse into error to a CLI error finally we'll Define a function called open and parse file and use the question mark operator to convert and propagate errors with ease another useful trait is from stir this tray allows you to parse user-defined types from a string for example here we have a struct called point with an X and Y field by implementing the from stirred trait we can write code which parses any given string into a point instance or fails if the string is malformed in this case we are specifying that the string should have coordinates defined inside parentheses separated by a comma then we are able to create new Point instances from strings this is especially useful when parsing string data from files the seventh mistake new row stations make is not taking advantage of macros in the standard Library the first useful macro is to do which allows you to compile your program with unfinished code this is especially useful when and prototyping in the following example we have a struct called DB which implements the database trait for this code to compile we must Implement all the required methods however let's say we only care about the connect method at the moment we can use the to do macro inside queries function body and have our code compile without actually implementing the method then in main we can create a new instance of mydb and call the connect method note that if we did call the query method the program would Panic at runtime the last set of useful macros I want to talk about is concat and format concat allows you to easily concatenate literals into a static string slice and format allows you to easily create own strings using interpolation both of these macros are useful when working with strings the eighth mistake new rust stations make is not using the tooling rust provides specifically cargo format and cargo clippy cargo format is a tool for formatting your rust code according to predefined style file guidelines this ensures your formatting is consistent and easy to read to run cargo formats simply navigate to the root of your rust project and run cargo format in your terminal you can also configure cargo format to run automatically on Save By installing rust analyzer and then enabling format on Save in settings.json clippy is a linter for your rust code it catches common mistakes and improves your code you can run clippy by executing cargo clippy in the root of your cargo project you can also add additional Arguments for example you can make complex code violations errors rather than warnings or you can Elevate all warnings to errors which is useful for continuous integration builds speaking of continuous integration it's very simple to set up clippy with GitHub actions in this case we are running clippy on git push and failing the build if any warnings appear now before we move on to the bonus mistake even experienced rust developers make let let me know if you're enjoying this video by hitting the like button and subscribing to the channel alright the last mistake I'd like to talk about has to do with structuring your code popular languages like python Java and JavaScript allow you to easily share and mutate objects however because of rust's ownership memory model you must be careful when combining multiple ownership and mutation Michael gives a good example of this in his blog so let's go through it together imagine implementing the logic for a game where a player must attack a group of monsters once the player inflicts enough damage they win first let's implement the logic in typescript we'll create a class named monster which has a health property a take damage method and a received damage property which stores a list of callback functions these functions are called whenever the take damage method is executed next we'll create a class called damage counter which will track the total damage the player has inflicted on damage inflicted will be used to attract total damage and reach Target damage will be used to check if the goal is reached finally we'll create a damage counter instance and an array of monsters add a callback which calls counter dot on damage inflicted for each monster and set up a while loop to inflict random amounts of damage on random monsters until the goal is reached in typescript this code is straightforward and works as you would expect now let's try porting it to rust instead of a monster class we'll Define a monster struct otherwise the code is very similar we have a take damage method which decreases self.health and calls each callback with the damage received and an add listener method which accepts a closure and adds it to the vector of callbacks we also implement the default trait to easily construct new instances of monster then in main will create a new damage counter instance create a vector of monsters add a callback which executes counter.on damage received to all monsters and run a while loop containing code which inflicts random amounts of damage on random monsters until the goal is reached pretty simple right well this code doesn't actually compile in fact there are several compile time errors the first error we get is cannot borrow counter as mutable as it is a captured variable in af enclosure the problem is the closure on line 56 captures counter as an immutable reference however counter dot on damage received needs a mutable reference to self we also get an error stating that we are borrowing counter mutably more than once because the closures are added in a loop an error stating counter does not live long enough because it's in a boxed closure and no lifetime annotations are specified and an error stating that we cannot immutably borrow counter because it is already borrowed as mutable all these errors stem from the strict borrowing rules in Rust to fix these issues the common approach is to introduce multiple ownership and interior mutability first we'll wrap counter in the RC smart pointer which enables shared ownership and the refsell smart pointer which enables interior mutability then we'll update the for Loop by cloning counter moving it into the closure and creating a mutable reference before calling on damage received finally we'll update the while loop to take an immutable reference to counter before calling reach Target damage with that our code is now compiling but you may be wondering what's the mistake here in general the mistake Crustaceans tend to make is overusing the RC and rough cell smart pointers or its counterparts Arc and mutex besides the downsides of increased code complexity and decreased performance you also get a decrease in memory safety because interior mutability works by checking borrowing rules our runtime instead of compile time this means if you're not careful your code can cause Deadlocks and crashes so what's the alternative the alternative is changing your API or code structure sure so that you're not holding long-lived references to other objects for example instead of storing callbacks in a field in the monster struct we could have the take damage method take a callback as input this would get rid of the need for smart pointers and simplify the main function if however passing in a callback isn't a good option for your specific use case there is another approach instead of accepting a closure the take damage method can return a summary of what happened as a result of inflicting damage then we can use the summary data to call on damage received as you can see programming in Rust requires thinking about how your code is structured and how memory is being used that's it for this video let me know what you consider to be common mistakes new rust stations make in the comments section below lastly make sure to get your free rust cheat sheet by heading over to let'sgarusty.com forward slash cheat sheet with that said I'll see you in the next one
Info
Channel: Let's Get Rusty
Views: 158,021
Rating: undefined out of 5
Keywords: Rust, rust 2023, rust for beginners, rust tutorial, rust 2022, rust developers, programming for beginners, programming 2023, programming in rust, coding in rust, programming tutorial, mistakes as a developer, programming mistakes, web development mistakes, common rust developers mistakes, newbie mistakes in rust
Id: PbR4ECFIckg
Channel Id: undefined
Length: 14min 14sec (854 seconds)
Published: Tue Jan 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.