8 deadly mistakes beginner Rust developers make

แชร์
ฝัง
  • เผยแพร่เมื่อ 29 เม.ย. 2024
  • New Rustaceans are an inquisitive bunch and want to dive into the language head first, but sometimes this leads to some common mistakes that beginners make. Today I am going to discuss 8 common mistakes that are made by new Rust developers or even more experienced Rust developers alike.
    Michael's Blog Post: adventures.michaelfbryan.com/...
    FREE Rust Cheat Sheet: letsgetrusty.com/cheatsheet
    Chapters:
    0:00 Intro
    0:32 Mistake 1
    1:11 Mistake 2
    1:55 Mistake 3
    2:40 Mistake 4
    3:37 Mistake 5
    4:50 Mistake 6
    6:47 Mistake 7
    7:48 Mistake 8
    9:05 Bonus
  • วิทยาศาสตร์และเทคโนโลยี

ความคิดเห็น • 281

  • @letsgetrusty
    @letsgetrusty  ปีที่แล้ว +11

    📝Get your *FREE Rust cheat sheet* :
    www.letsgetrusty.com/cheatsheet

  • @Possseidon
    @Possseidon ปีที่แล้ว +207

    3:15 when just returning true/false from match arms, it can be written even more concise using the matches! macro:
    fn can_publish_blog(role: Role) -> bool {
    matches!(role, Role::Admin | Role::Writer)
    }

    • @zohnannor
      @zohnannor ปีที่แล้ว +17

      If I'm not mistaken, clippy would even point this out :)

    • @luismolon
      @luismolon ปีที่แล้ว +3

      Cool

    • @AlexanderKrivacsSchrder
      @AlexanderKrivacsSchrder ปีที่แล้ว +20

      I was honestly baffled that an expression that could just've been `role == "Admin" || role == "Writer"` was made into what basically amounts to a `if { true } else { false }` kind of setup.

    • @shambhav9534
      @shambhav9534 ปีที่แล้ว +1

      @@AlexanderKrivacsSchrder All humans suffer from this, lol.

    • @MartinHabovstiak
      @MartinHabovstiak ปีที่แล้ว +18

      Instead of matches it would be better to exhaustively match on the enum to ensure not forgetting to handle new variants.

  • @YanVidz
    @YanVidz ปีที่แล้ว +81

    1:28 For mistake #2, there is a common mistake within it: *Overusing vectors* . A lot of times, beginners will prefer creating vectors whenever they need an arbitrary amount of things. This is indeed what vectors are for, _when they are useful_ .
    Vectors are relatively costly and are meant for _storing_ data in a longer timespan. If you are collecting data into a vector just to perform operations on the vector and then no longer need it thereafter, then you are doing it wrong. The fix here is to not use a vector at all.
    In your minimal example, the full scale is not seen, so what you did _might_ have been necessary, but if you just wanted to use the new vector to do something with each element and then discard the vector, then all you needed to do is for-loop through the same iterator but without the `collect` method, which avoids creating a vector.
    If instead you do need a vector because some other function requires it or for some other reason, then you should look into why you have a vector in the first place. There would be no need to have a vector twice in your code if one vector transforms into the other. The fix in this case is to look for how to avoid creating the first vector, and just using an iterator like in my previous fix to collect into the desired vector directly. If you got the first vector from a function, then shame on that function; it should have returned an iterator instead of allocating a vector. If you created that function, then here's what you can do to fix the return type:
    Allocating and returning a vector from a function is often undesirable because you are forcing an allocation which the user might not need. Instead, return an iterator without using `collect`, which avoids creating a vector. The returned type signature will look like this: `impl Iterator` (change `i32` to whatever type of element the iterator is iterating through.) This is called an "opaque type", which hides the often complex full type signature that you are actually returning, and only exposes what relevant trait you are trying to provide. (If you returned the true iterator type instead of a vector, it would look a lot more confusing, or it might not even be possible.) For more information on opaque types, here's the official reference: doc.rust-lang.org/reference/types/impl-trait.html

    • @user-bt8tg7ct4i
      @user-bt8tg7ct4i 7 หลายเดือนก่อน

      example?

    • @macchiato_1881
      @macchiato_1881 6 หลายเดือนก่อน

      That's interesting. You can do that in Rust?

    • @mikhalpalych
      @mikhalpalych 5 หลายเดือนก่อน

      Said above in a nutshell: if you have **a lot of short** vectors and you need to perform operations on each item of each vec but without creating a resulting vec, it *might* be better to turn vectors into so called "adaptor iterators" without consuming them (*via .collect()*) and then iterate over resulted iterators using regular for loop (under the hood for loop calls .next() method of iterators).
      But there is a better (more concise) way for same result, it's done via .into_iter() method (*instead of .iter()*): myvec.into_iter().map(...).for_each(...);
      Anyway, if you are beginnner, relax and use vectors. And in order to handle more gracefully such specific cases as described put into your todo list reading (and comprehending) chapter about iterators in rust.

    • @NYKevin100
      @NYKevin100 3 หลายเดือนก่อน

      Even if you *do* need a container, you don't always need a vector. You can collect() into a boxed slice, which is a fixed-size allocation that doesn't need to bother with the full complexity of Vec. The only reason to collect() into a Vec is if you're going to add or remove elements later. Vec also supplies an into_boxed_slice() convenience method for cases where you don't have an intermediate iterator.

  • @orterves
    @orterves ปีที่แล้ว +241

    Naturally the advanced error is object oriented mutability, with the incorrect solution being to slop more mutability onto the code until it complies and the correct way being to just make it more functional with better separation of concerns

    • @stevenhe3462
      @stevenhe3462 ปีที่แล้ว +42

      Using Rust for almost purely functional code is considerably easy whereas using it for almost purely object-oriented code is a huge pain in the ass.

    • @orterves
      @orterves ปีที่แล้ว +5

      @@stevenhe3462 absolutely, but even better is even though the improved code here isn't fully functional, the mutable objects that it does have are mutable in a way that you can trust.

    • @calder-ty
      @calder-ty ปีที่แล้ว +5

      If the refcell is encapsulated so that only one struct has control over the interior meaning mutability then most of the concerns about safety go away, at a slight cost to performance. Telling people the solution is to restructure their entire API and structure (which is the suggested solution) is a huge cost.

    • @orterves
      @orterves ปีที่แล้ว +11

      @@calder-ty sure, but hopefully this provides an insight so that the code isn't built that way in the first place
      Especially since it's the compiler complaining about it, rather than some obscure bug in production

    • @stevenhe3462
      @stevenhe3462 ปีที่แล้ว +9

      @@calder-ty That is why we should better do it that way in the first place. Having object oriented mutability contributes greatly to the complexity to refactor code. And, mutability itself introduces high difficulty to parallelize the execution.

  • @thingsiplay
    @thingsiplay ปีที่แล้ว +578

    Common mistake number 0: Waiting too long to start learning Rust.

    • @vishnuc2682
      @vishnuc2682 ปีที่แล้ว +46

      And its close cousin: giving up too quickly without working through the initial hard part of learning Rust where you’re constantly battling the borrow checker.

    • @alessandrorossi1294
      @alessandrorossi1294 ปีที่แล้ว +12

      The real mistake is learning Rust at all. If you're a frontend developer learn javascript. For everything else there's Python.

    • @thingsiplay
      @thingsiplay ปีที่แล้ว +20

      @@alessandrorossi1294 I disagree. Python was my main language for over a decade. And i started Rust because it complements Python very good. I use Python or Rust for whatever the situation needs to. And for simple things I can use Bash (shell scripting).

    • @ziiirozone
      @ziiirozone ปีที่แล้ว +23

      @@alessandrorossi1294 python only works when you don’t need performance, and telling that it works already means tolerating a lot of defaults. I used to program only in python and after learning rust I always miss the type system, the errors messages and the overall safety of rust. You should really try learning rust, it’s coming for the web as well.

    • @alexlarex7773
      @alexlarex7773 ปีที่แล้ว +15

      ​@@alessandrorossi1294 Languages are usually designed for a specific set of problems. Of course you can write a website front end in C++ or make JS code run on a microcontroller, but it doesn't mean that that's a good idea. Python has its place, it's a good language, especially for small stuff, purely scientific stuff, or stuff that is needed fast and not necessarily rock solid. But there is a lot of stuff apart from frontend that python should just never be used for.
      As a programmer with experience in a bunch of different fields, very rarely can learning a new technology be a mistake. Even a shitty technology can provide useful insight, and any learning process at all provides some useful mental exersize, to keep you flexible enough to be able to solve problems well and fast.
      Rust approaches memory safety and compile time error checking in quite a unique and novel way, that it's worth learning even just for the sake of knowing, that those kinds of things can be approached this way.

  • @naughtrussel5787
    @naughtrussel5787 ปีที่แล้ว +22

    The last one is extremely helpful. It's often hard to wrap up my mind around this inability of porting code line by line.

  • @FiniteSteakMachine
    @FiniteSteakMachine ปีที่แล้ว +77

    If you're going to turn warnings into errors in CI, you should also pin the Rust toolchain version used, otherwise new warnings can be added in any minor version (especially in Clippy). Almost all of my projects hit a new clippy finding after every couple of Rust updates, if they hard-blocked CI then it would be a huge nuisance.
    Fun fact: You can get out ahead of some of these checks by installing the nightly toolchain and running cargo +nightly clippy --all-targets. It's like those "new lint from the future just leaked" memes except real.

  • @MegaJambo991
    @MegaJambo991 ปีที่แล้ว +19

    I wrote an interpreter as my first project in Rust, and I encountered that last problem exactly. I had closures that would have a reference to the enclosing scope, and the borrow checker was very upset with me. I tried to fix it using lifetime annotations, but I quickly got way too confused. I managed to get it to work by slapping Rc and RefCell on things, but it felt really wrong. Thanks for sharing ideas about how to avoid these types of issues in the future!

  • @paulgupta2454
    @paulgupta2454 ปีที่แล้ว +26

    The community needs more of these friendly newbie resources! Keep it up!

  • @GeekMasher
    @GeekMasher ปีที่แล้ว +20

    Love mistake 6 as I did this and didn't use some of the amazing built-in traits. One I recommend looking at is the `Display` trait to customise the output of a println! or format! marcos.

  • @addisonmigash8227
    @addisonmigash8227 ปีที่แล้ว +9

    11:05 monsters could be better-defined as:
    “let mut monsters = vec![Monster::default(); 5];”

  • @zohnannor
    @zohnannor ปีที่แล้ว +9

    Nice video! However, I disagree with its thumbnail. There's nothing bad with `Rc` on its own, thumbnail is misleading. I'd instead put for loop with i += 1 and array indexing, a more common "mistake" due to poor knowledge of the lang.

  • @jongeduard
    @jongeduard ปีที่แล้ว +1

    Thanks for your video. Especially your last, more advanced subject of the monsters game with the stored and shared closure references. I like that example also from the aspect of functional programming, in which the lack of state is an important aspect. Having everything directly exchanged between functions, including those closures which you don't store anymore, makes your program more functional kind and less of the imperative style coding kind. This is nice.
    I would also like to mention that I see multiple points in which the The Book can still improve here.

  • @letsgobrandon2523
    @letsgobrandon2523 ปีที่แล้ว +15

    You know, it would be really helpful to have a video expounding on each of these points, as it was hard to understand exactly what I need to learn/change in my programming from such short examples - however, it was also apparent from the examples that there are nuances I'm missing with my Rust programming.

  • @73nko
    @73nko ปีที่แล้ว +3

    awesome video! I've been reflected myself in much of the topics you have covered, and many others I've already fixed them. hanks for your work!

  • @linkernick5379
    @linkernick5379 ปีที่แล้ว +6

    The most fundamental one is the last one, on the mutability. Unfortunately it can not to be learned so easily, one should pass thru functional programming at first, I think.

  • @andredasilva6807
    @andredasilva6807 ปีที่แล้ว +9

    keep up the fantastic rust videos. they are always helpful and very intresting. one of the reasons why i love rust

  • @cna9708
    @cna9708 ปีที่แล้ว +1

    Very helpful! Rust by example is amazing at the start. Then these problem example & improvement versions help a lot to for deeper understanding. These are a little harder to come by, thanks for the work! Maybe one idea for future videos: Have you thought about displaying the base and improved versions side by side? I found myself rewinding several times at each topic. Its probably bad for visibility while watching on a smartphone, but maybe there is a way add it in after every example 2 seconds just to pause and read or something like that..

  • @nocodenoblunder6672
    @nocodenoblunder6672 11 หลายเดือนก่อน +1

    @ 3:30 don’t forget the relatively new let else statement which can be used for guarding clauses.
    It is similar to if let but always assigns, unless you call return in the else block.

  • @KiranasOfRizon
    @KiranasOfRizon ปีที่แล้ว +6

    Was not aware of the array_windows and windows methods on arrays. Might start using this more often... although right now, array_windows is only in nightly, so the windows method may be preferable.

  • @Morgan_iv
    @Morgan_iv ปีที่แล้ว +4

    Mistake 2: overusing slice indexing
    6:37: Making actual mistake when using slice indexing

  • @porky1118
    @porky1118 ปีที่แล้ว +4

    I also don't always implement the error trait on my error types. I tried to get around proper error handling for some time. But this error derive crate seems helpful. I might start using it.

  • @Milky____
    @Milky____ ปีที่แล้ว +2

    I'm new to rust and this video help a ton, especially the end when you used game logic to explain things

  • @draakisback
    @draakisback 11 หลายเดือนก่อน +7

    Most of these were pretty avoidable when I started learning rust. Maybe it's because I came from a functional programming background; understanding the value of enums, results and option, using map, filter, reduce etc. Now that being said, the biggest issue I had with rust when I first started is that I treated it like a functional language. Rust is first and foremost a procedural and imperative language with functional features. If you try to treat it as a purely functional language you're going to be in for a lot of pain. I can't tell you how often I bounced off the borrow checker because of this. Anyway, good video; all this is really good advice and it's hard to remember that this stuff is not obvious when you've been using the language for 8 years.

  • @Code12x
    @Code12x ปีที่แล้ว +3

    A mistake that I want to make a lot is creating a variable without a value, then going into a loop and assigning the value of the variable inside the loop. Finally, trying to use the variable after the loop causes some sort of lifetime error.

  • @JTCF
    @JTCF ปีที่แล้ว +3

    array_windows() is nightly... I highly discourage usage of nightly. Especially in videos directed to newbies.

  • @maxday_coding
    @maxday_coding ปีที่แล้ว +3

    Awesome content as usual! Thanks for sharing those mistakes!

  • @thebarnowlsmusic
    @thebarnowlsmusic 4 หลายเดือนก่อน +1

    I like the javascript to rust example, it made things more easier to understand. Could you do more of them if most people find it useful :) its sure as hell useful to me.

  • @JelloPuddingMaster
    @JelloPuddingMaster 11 หลายเดือนก่อน +1

    4:59 I should have known about Default, its so useful.

  • @kirillgimranov4943
    @kirillgimranov4943 ปีที่แล้ว +3

    TBH I had a lot of pain exactly when was struggling with a bad ownership model in my project

  • @ErikBongers
    @ErikBongers ปีที่แล้ว +6

    Excellent advice for beginners like me.

  • @kennystrawnmusic
    @kennystrawnmusic ปีที่แล้ว +9

    Might want to note that many of the underused standard library traits mentioned in Mistake 6 are technically core library traits that the standard library depends on - which means “#![no_std]” (i.e. kernel) developers like myself don’t have an excuse either.

  • @user-gl9yo8rz8k
    @user-gl9yo8rz8k ปีที่แล้ว +3

    Вот это то, что надо! Вроде бы базовые вещи, но такие важные и нужные.

  • @ChristopheTroestler
    @ChristopheTroestler ปีที่แล้ว

    Informative video - as usual! 👍

  • @dungeon4971
    @dungeon4971 ปีที่แล้ว +2

    one common mistake I made when I started with rust was to overuse copy

  • @hakanakdag9491
    @hakanakdag9491 5 หลายเดือนก่อน +1

    I am trying to learn Rust. I have c/c++ background. But I havent used them for a long time. My initial impression is, rust looks extremely sophisticated. To start writing actual code, I found my self to learn a lot of rules and coding techniques. It is definetely not an ordinary language at all. But I am not thinking to give up. I want to build a command line tool. Lets see how it will go :)

  • @l4fourier75
    @l4fourier75 ปีที่แล้ว

    Very nice and interesting video! One point i found no video at all to is how to write a plugin for nushell. Since nu scripts will be compilable one day, it could be very powerful to be able to write integrations in Rust with more functions.

  • @twentyeightO1
    @twentyeightO1 ปีที่แล้ว +8

    One fatal mistake most make is not using Rust.

  • @HoloTheDrunk
    @HoloTheDrunk 10 หลายเดือนก่อน +1

    10:55 small detail but it might be worth using available syntactic sugar given the target audience of the video.
    So in this case adding a Clone derive to Monster, which allows for
    ```rs
    let mut monsters = vec![Monster::default(); 5];
    ```

  • @samansamani4477
    @samansamani4477 ปีที่แล้ว

    Good and helpful as always.

  • @tordjarv3802
    @tordjarv3802 ปีที่แล้ว +6

    A note on mistake 2. When I tried to use the array_windows method I get "error[E0658]: use of unstable library feature 'array_windows'". After some researching array_windows is currently an experimental feature and only available for rust Nightly. Therefore, I think that it is a bit irresponsible to claim that not using it is a mistake. As of writing I have 1.66.1 installed while the latest official release is 1.67.0 and array_windows is experimental in both.
    Otherwise I think you made a good video, with nice examples.

    • @angeldude101
      @angeldude101 10 หลายเดือนก่อน +1

      `windows` on its own should be used instead of `array_windows` if you want to avoid unstable features. They're basically the same, except one takes a size parameter at compile time and gives fixed-length arrays, while the other takes a size parameter at runtime and gives slices that it promises are all with the right size. As you can see from my description, it's pretty clear which I think is better, but the reason it's unstable is because of its use of const-generics, so it wasn't possible to implement for much of Rust's life.

  • @chrisnocker3437
    @chrisnocker3437 ปีที่แล้ว +3

    Thanks for the video, I liked it and there are some changes I will try to focus on in the future. I’ve been using Rust for a while now and my feedback for this video would be that it was too fast paced. I think a beginner would need more verbose explanations for each of the common mistakes… maybe next time you could highlight each change that was made in you editor?

    • @ericbwertz
      @ericbwertz ปีที่แล้ว +1

      Being in this same situation, I expected to not grok all of this now, but would feel "that tingle" when I got to the language parts that I haven't run into yet. The thumbnail nearly scared me off, but I consciously decided that it wasn't for me, but instead for my future &self.

  • @SkullJakob
    @SkullJakob ปีที่แล้ว +1

    This video was worth watching for the todo! macro alone. I've wasted so much time commenting out return values of functions since the rust analyzer would complain

  • @Holobrine
    @Holobrine 7 หลายเดือนก่อน

    I think the code structure at the end is odd. Closures should avoid capturing things if possible, and should be more purely functional. Capturing mutable state is an indication of side effects. I would say here, the damage counter should borrow the monsters, iterate over them, and mutate itself.

  • @eligoldberg5499
    @eligoldberg5499 8 หลายเดือนก่อน

    Why is pattern matching better than an if statement when checking for a boolean state? (Is_some)

  • @bayoneta10
    @bayoneta10 ปีที่แล้ว +1

    I just have a question related to Smart Pointers. Are there some best practices about when to use Smart Pointers? Thank you a lot for your content. Congrats once more

    • @SimonBuchanNz
      @SimonBuchanNz ปีที่แล้ว +4

      In data types (eg structs) use the cheapest that works, as a rule of thumb: T before Box before Rc before Arc. Basically never use &T in data types unless you know what you're doing. For transient references like parameters and local vars you should nearly always use just &T unless you have a reason to use something else.
      Very generally, there's little cause to use Rc in most well designed code, Arc is mostly for fiddly mutithreaded internals, so really you are mostly choosing between T and Box. The main thing Box gives you is that you don't need to worry about the size of T while still having ownership, so it's for things like preventing infinite size types in trees, making it cheaper to pass around big types, and enabling dynamic types (Box).

    • @bayoneta10
      @bayoneta10 ปีที่แล้ว +1

      @@SimonBuchanNz wow! I appreciate your response! Thank you a lot!

  • @mangopolice
    @mangopolice ปีที่แล้ว +8

    I loved the Rc/RefCell explanation

  • @user-lc5iy2hf3c
    @user-lc5iy2hf3c 10 หลายเดือนก่อน

    For the example of array_windows, are you sure the revised code is more efficient than the one using index?

  • @JoaoBapt
    @JoaoBapt ปีที่แล้ว +1

    The last "error" is actually the reason I decided not to keep messing with Rust and went back to C++, C# and other languages.

    • @user-kw1lx9rf2s
      @user-kw1lx9rf2s ปีที่แล้ว +2

      Right, the life is way more fun squashing bugs, properly designed software is boring.

  • @aleksanderkrauze9304
    @aleksanderkrauze9304 ปีที่แล้ว +2

    While I agree that excessive usage of `Rc` is a sign of bad design you would really need to work hard to cause a deadlock. And there is no decrease in memory safety. Unless you touch `unsafe`, your code **will** be memory safe.

    • @user-kw1lx9rf2s
      @user-kw1lx9rf2s ปีที่แล้ว +2

      My first program in Rust was a parser for my own programming language, and used multiple levels of Rc as from a tutorial, and after a while I was getting stuck and confused on these borrows, so I realized why do I go through so much to avoid receiving self as a mutable reference when I can just accept self as a mutable reference. And I did. And my code became 2-3 times shorter and I never had a single issue I was stuck on. To be honest, I'm not sure what else would one use Rc/RefCell, it was my only encounter with it.

  • @sunhsiang6644
    @sunhsiang6644 ปีที่แล้ว

    Help a lot👍🏻

  • @emtbbam2895
    @emtbbam2895 4 หลายเดือนก่อน

    Sorry, I have a question: In the Bonus section, last slide, the counter.on_damaged_received is called. But it was removed in the 2nd approach in impl Monster. How does this work? Btw.: This video helps me a lot!

  • @xE92vD
    @xE92vD 4 หลายเดือนก่อน

    Great tips, thanks.

  • @gianmarcoalarcon6185
    @gianmarcoalarcon6185 ปีที่แล้ว +1

    In my case, I am using too much unsafe code to deal with pointers, interior mutability u.u
    Thanks for the video

  • @xyz-vrtgs
    @xyz-vrtgs 8 หลายเดือนก่อน

    In mistake number 6 you did what you preached not to, and indexed into an array whithout checking if it was even empty.

  • @zyxyuv1650
    @zyxyuv1650 ปีที่แล้ว

    Do you have a linter setup for this?

  • @techzoneplus
    @techzoneplus ปีที่แล้ว

    Thanks, super useful

  • @xBZZZZyt
    @xBZZZZyt ปีที่แล้ว

    2:19 why you return int (32bit signed integer) but array length is size_t (64bit unsigned int)

  • @JorgetePanete
    @JorgetePanete ปีที่แล้ว

    What opinions do you have on the typenum crate and similar? If I want compile time constraints on a string or number without sacrificing readability is it good?

    • @swapode
      @swapode ปีที่แล้ว

      I'm sure there still are circumstances where it's useful, but a lot of what's advertised can be done with const generics now.
      struct Foo {
      data: [i32; N]
      }

  • @dynamite-bud
    @dynamite-bud ปีที่แล้ว

    I am so happy to say that Michael Bryan is my mentor.

  • @kellyrankin8844
    @kellyrankin8844 ปีที่แล้ว +2

    I'm struggling a bit to fully understand the last one. I agree the smart pointer stuff seems complex and risky, but I don't quite follow what is being suggested for the alternative.

    • @itellyouforfree7238
      @itellyouforfree7238 ปีที่แล้ว

      passing around data instead of closures containing references to objects whose lifetime you can hardly keep track of

    • @blackwhattack
      @blackwhattack ปีที่แล้ว

      i am confused too.
      1. why the DamageCounter needs to be updated separately and it is not enough to do all the calculations in .take_damage() is not explained,
      2. why do there need to be many damage callbacks requiring the Box> is not explained, as a single callback field could be stored inside the struct with generics and no allocation with Box would be necessary
      3. DamageCounter could wrap the damage in a Cell, and then use (&self) method signatures

    • @Buttons841
      @Buttons841 4 หลายเดือนก่อน

      @@blackwhattack When damage is taken the UI needs to be updated, and a warning sound needs to be played, and Bob on the other team working on the enemy AI and is thinking about making the boss taunt the player when damage is taken.
      Or, more generally, there are a lot of things we want our own code to do in response to damage, and there may also be a lot of things in other code (yet to be written, maybe not written by us) that also wants to respond to damage. This results in a lot of callbacks.

  • @lisovyy
    @lisovyy ปีที่แล้ว

    this is awesome, thanks

  • @fabiopetrillo
    @fabiopetrillo ปีที่แล้ว +1

    Amazing video, congrats!

  • @NotAFoe
    @NotAFoe ปีที่แล้ว

    Thx very much 💖

  • @kajacx
    @kajacx ปีที่แล้ว

    Damn, that's the first use of the "windows" method I've seen. Good job.

  • @TON-vz3pe
    @TON-vz3pe ปีที่แล้ว

    Now this video is very useful. Cheers

  • @TarasZakharchenko
    @TarasZakharchenko ปีที่แล้ว

    Wow I did not know most of those cool features!

  • @jeffg4686
    @jeffg4686 ปีที่แล้ว +1

    Array_windows docs have example like this:
    let iter = slice.array_windows::();
    I'm assuming that's incorrect... 2 isn't a type...

  • @adiletmyrzabekov883
    @adiletmyrzabekov883 ปีที่แล้ว

    What theme is that ?

  • @ANSIcode
    @ANSIcode ปีที่แล้ว

    6:28 that parsing code will panic if passed "(1,2,3)"? Seems like an example that teaches bad habits?

  • @bravo________87372
    @bravo________87372 ปีที่แล้ว

    Unwrapping options is the bane of my existence

  • @jordisarrato331
    @jordisarrato331 ปีที่แล้ว

    Very interesting the last part of the game

  • @narigoncs
    @narigoncs ปีที่แล้ว

    There's no way that CI works, right? There's no cargo installed in the base actions/checkout image?

  • @chenjaike950
    @chenjaike950 9 หลายเดือนก่อน

    functional programming approach reduce chances of using smart pointer

  • @avisalon4730
    @avisalon4730 ปีที่แล้ว

    I don't know. I am learning Rust not too much. But the last example seems like Rust memory safe but overcomplicated. (My main work is Typescript developer 5 years)

  • @BaptistPiano
    @BaptistPiano ปีที่แล้ว +3

    I love how he gives instructions with the assumption that vscode is the only way to type rust code

    • @edwin5145
      @edwin5145 ปีที่แล้ว

      What here suggested that? Perhaps only the continuous integration thing but that is doable in many other ways.

  • @romanstingler435
    @romanstingler435 ปีที่แล้ว +2

    Common mistake number -1 Not bothering to read the docs

  • @Taurdil
    @Taurdil ปีที่แล้ว

    4:45 What library?

  • @pineiden
    @pineiden ปีที่แล้ว

    Excelent tips!

  • @31redorange08
    @31redorange08 ปีที่แล้ว +4

    Deadlocks with Rc?

    • @brentsteyn6671
      @brentsteyn6671 ปีที่แล้ว +2

      I was also thinking that.🤔

    • @vishnuc2682
      @vishnuc2682 ปีที่แล้ว +2

      And a close cousin: not using Weak and creating cyclic references that never get cleaned up.

    • @TON-vz3pe
      @TON-vz3pe ปีที่แล้ว +1

      Yeah, how is that possible? Rc allows us to have multiple owners, but we still have to follow the 3 prime borrowing rules. Dead locks in Rust, is that even possible?

    • @Starwort
      @Starwort ปีที่แล้ว +1

      @@TON-vz3pe you can deadlock a rwlock, but refcell just panics if the borrow rules are violated

  • @GermanKuber
    @GermanKuber ปีที่แล้ว

    Hi. First I would like to tell you that, I love your videos, are super educational and I really learn a lot with all of it.
    Thank you for share you knowlodge.
    I have a question. I am looking for a emulator or something that show me the status of the heap and the stack while I debug the code.
    DO you know some tool or extension like this?

  • @wtcxdm
    @wtcxdm ปีที่แล้ว +1

    I am about to start reading the smart pointers chapter (ch 15) in the book. I actually hesitated a bit before clicking on this video because it looked difficult. Glad I watched this anyway.

  • @aqua3418
    @aqua3418 11 หลายเดือนก่อน +1

    6:08 It's worth noting that `thiserror` allows you to easily implement `From` by annotating with `#[from]`

  • @jeffg4686
    @jeffg4686 ปีที่แล้ว +1

    The unfortunateness of this video is that those who made the deadly mistakes aren't with us anymore, so they can't learn from the video.

  • @MohammadRajablooloverajabloo
    @MohammadRajablooloverajabloo ปีที่แล้ว +1

    why not just return the damage? this method call is synced, no need for a callback 13:15. and no extra struct in 13:32, what do you think?

    • @Gramini
      @Gramini ปีที่แล้ว +3

      That would be the same idea as using an "AttackSummary", just skipping the struct. If you only need one metric, then returning only a number works fine.

  • @beastle9end499
    @beastle9end499 ปีที่แล้ว

    The mistakes experienced rust developers make would be interesting

  • @bayoneta10
    @bayoneta10 ปีที่แล้ว +2

    Huuuuuuuge! Congrats for that video! Really useful! 🎉🎉

  • @kennyhouse8662
    @kennyhouse8662 ปีที่แล้ว

    Can someone explain how the first example is unnecessary indirection?

    • @user-kw1lx9rf2s
      @user-kw1lx9rf2s ปีที่แล้ว

      String is an owned type stored on the heap, basically it's an indirection layer for &str. In this case you do not need to store on the heap when you have a static alternative which is way more performant. And you get both string types supported because Rust automatically infers &str from String and also accepts &str.

  • @redpillsatori3020
    @redpillsatori3020 ปีที่แล้ว

    Can anyone recommend a good book on Rust that explains basic concepts for a beginner?

    • @BryanBaron55
      @BryanBaron55 ปีที่แล้ว +7

      Nothing better than it's official documentation. It's so concise and has a straightforward vocabulary, increasing for that reason the ease of understanding the concepts you need to dive into. Indeed, I recommend you to have a strong programming background to be able to actually understand what you're reading, and of course, learning about Rust and its ecosystem.

    • @qwertycomp9618
      @qwertycomp9618 ปีที่แล้ว +4

      @@BryanBaron55 Yeah definitely, the Rust Book is an absolutely awesome resource

  • @truongquockhanh4885
    @truongquockhanh4885 ปีที่แล้ว

    great video

  • @porky1118
    @porky1118 ปีที่แล้ว

    2:15 I wouldn't say, it's always bad to use zero as a special value, though. I still do that in one of my programs. But I get why it's not considered good practice.

    • @user-kw1lx9rf2s
      @user-kw1lx9rf2s ปีที่แล้ว +1

      What's wrong with creating a properly named enum instead of meaningless error integers?

    • @porky1118
      @porky1118 ปีที่แล้ว

      @@user-kw1lx9rf2s Why do you think, I'm talking about error integers?
      I think, I basically had an index, but 0 did represent some default elemen, while 1 represented element 0 of an array.

    • @user-kw1lx9rf2s
      @user-kw1lx9rf2s ปีที่แล้ว +1

      @@porky1118 By returning some hard coded default value you cannot know if a function failed or not. I think by default your should use option, but if you need an infallible version, create a separate function like search_or(default: usize) -> usize.

  • @ilikemorestuff
    @ilikemorestuff 2 หลายเดือนก่อน

    Reductive coding supports less dependencies, in less languages, on unsupported devices.

  • @m.sierra5258
    @m.sierra5258 ปีที่แล้ว

    "If you are not careful, your code can cause deadlocks and crashes" - NOT QUITE CORRECT. Deadlocks yes. But a 'crash' is usually some kind of undefined behavior. And although it can deadlock, Rust programs can **not** contain undefined behaviour as long as we don't use "unsafe".

  • @have-bear
    @have-bear ปีที่แล้ว +1

    You should includes matches macro.

    • @tristao9264
      @tristao9264 ปีที่แล้ว

      what's wrong with the matches macro?

  • @user-hy5cx9iu3l
    @user-hy5cx9iu3l 10 หลายเดือนก่อน +1

    Дякую!

  • @zyxyuv1650
    @zyxyuv1650 ปีที่แล้ว +1

    So I asked if you have a linter setup for this and got no responses...I am guessing the reason is because it's too difficult to do.
    But why is it too difficult? Can't we use AI to detect all kinds of this class of problems and even more obfuscated/spread out/deeper ones?
    There's an issue of "Do we even have enough free time to make an AI linter that can do this? No. It's not worth the time it takes to figure out how warn against everything a coder should know how not to do on their own."
    But maybe that's invalid ...

    • @swapode
      @swapode ปีที่แล้ว +1

      I think most of these simply go beyond a linter and go more into code generation territory: You need to understand the greater context to make a decision. Even something as simple as &String vs. &str depends on the context. But if an AI system understands the greater context, why not have it generate the code in the first place instead of just pointing out when you make mistakes? Things certainly seem to move in that direction...
      Also, there are already clippy flags that check for some of these. For example clippy::new-without-default will trigger when you have a Something::new() not taking parameters but don't implement Default.

    • @svenyboyyt2304
      @svenyboyyt2304 หลายเดือนก่อน

      It's built into Rust

  • @noahprussia7622
    @noahprussia7622 ปีที่แล้ว

    You say 1:45 is the improved version. Is the goal not readable code? People make "Mistake 2" and will continue to make it because its about making it readable. Getting on your podium and stating its a deadly mistake makes developing Rust code harder for beginner developers. They are going to use each and every Rust feature when the necessity is not there, bloating their code. Why wasn't mistake 2 corrected by showing a guarantee that the vector won't be improperly accessed, or having a method for dealing with that scenario? Rust can solve this issue in a simpler way.
    An actual deadly mistake is including several hundred unnecessary /unclear dependencies then uploading the project.
    If we want a public standard for proper code and coding techniques, why are we not just following the ones that exist already? The ones that emphasize readability (for newer developers, for team projects, for ease of mind retainability), efficiency (no need to waste resources checking the index of an array in a for loop, that can be the compiler's job), safety, portability, etc. Mistake 2's correction is counterintuitive at worst and confusing at best. It has no place being considered "correct" or "preferred"

  • @porky1118
    @porky1118 ปีที่แล้ว +1

    9:00 I consider myself to be a experienced Rust programmer, I'm using Rust for 5 years maybe, but I still do or recently did some of the "beginner" mistakes. For example I didn't use clippy until maybe half a year ago.

    • @porky1118
      @porky1118 ปีที่แล้ว

      But not using Rc and structuring programs differently is one of the first things I learned when using Rust. Probably after a year or so.
      I guess, that's because I think, I'm smarter than everyone, and therefore ignore advice from other people and only look things up things, when I don't find solutions myself. So I only learn, what's really necessary/useful from experience. And using Rc is just annoying to work with, so I had to find a way to work around it.

  • @awwastor
    @awwastor ปีที่แล้ว +2

    I don’t think sentinel values are always the wrong choice. If you have a type that is stored and instantiated millions of times, using some invalid state instead of an enum or flag can provide a significant performance boost (thanks to the memory reduction)

    • @Matheus-yx6qb
      @Matheus-yx6qb ปีที่แล้ว +6

      That way of thinking make sense, but probably is wrong. Enums don't have a static ABI or a defined memory layout (you can force them to have it, so you can communicate with C code, but that's not the default behavior), because of that, the compiler will try to optimize the memory use and performance of the Enums. The most famous optimization is the "null pointer optimization", and variations of that optimization with another types besides pointers may be possible.
      Basically, if you have an enum with two variants, with only one of them carrying a type, if that type have an "invalid value", that value will be used to represent the second variant of the enum (in that case, the tag of the variant isn't included in the variants). This optimization occour all the time with options.

    • @awwastor
      @awwastor ปีที่แล้ว +2

      @@Matheus-yx6qb That’s true, but I’m talking about some more complex situations, where you’d have more than one sentinel value or the value would say something about how to interpret the rest of the value (similarly to how nanboxing is done). And while more optimisations could be added in the future, I don’t really care about how performant my code could be.

    • @Matheus-yx6qb
      @Matheus-yx6qb ปีที่แล้ว +1

      @@awwastor I understand that may be cases that cannot be space optimized by the compiler, but I didn't quite understand your examples. If there are multiple sentinels, I think the compiler would choose another invalid value to those variants (that specific optimization isn't restricted to enums with two variants)

    • @AndrewBrownK
      @AndrewBrownK ปีที่แล้ว

      Sounds like a nightmare. No thanks.

    • @AndrewBrownK
      @AndrewBrownK ปีที่แล้ว +1

      “Can provide a significant performance boost” then “I don’t care about how performant”

  • @stanislauyan3204
    @stanislauyan3204 ปีที่แล้ว

    Mistake #4 is inside the code for mistake #6… 🎉