[–] 3 points 7 months ago

I always like "by example"s for learning languages - here's Rust's.

I'd probably make a project with it. Maybe a CLI tool using clap_derive and some crate that does something neat that you want to do. Depends what you're interested in I guess.

I wouldn't recommend trying to do leetcode problems with Rust because they are obsessed with linked lists and linked lists are awkward in Rust.

Also I wouldn't recommend making a game or GUI app with Rust yet since the ecosystems there are immature.

A microcontroller project using Embassy is probably a fun way to learn too but I haven't actually tried it yet.

  • source
  • [–] 2 points 7 months ago (5 children)

    Domains are, sure but the space is much much larger. With namespaces the space is for example namespace x crate instead of just crate. With domains it's impossibly large. And if you introduce some kind verification with domains e.g putting something in the DNS TEXT entry, or calling a well-known path, or or or, you basically can't squat anything well-known anymore.

    As for github, you must have a github account to create a crate on crates.io. to my knowledge there is no alternative crates registry. Point me to one if you do, because I'd be grateful and willing to publish my crates there.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago

    @anything_but_windows I usually like to mix my learning experience with an interesting toy project (github.com/codecrafters-io/bui) along with the material suggested here

  • source
  • [–] 10 points 7 months ago* (last edited 7 months ago)

    (edit: I see I missed the part about being fun, but I don't know of better alternatives)

    I learnt with the one on the main site, "the Rust book" which is good for explaining concepts and is (or certainly was) considered the standard textbook.

    Rust by Example is good for a quick start in how to do various things, but imho is most valuable for experienced programmers and as a cheatsheet-style reference.

    Once you start writing your own code, it's useful to look at Blessed.rs to show what are the fairly standard options for basic libraries for logging, http, etc that you might have expected to be in the standard library. It's useful to be pointed at something that's good enough instead of spending hours investigating the various competing crates.

  • source
  • [–] 2 points 7 months ago

    Your second point has been a focus area for them for years, and we've seen it improve with async fn in trait, async closures, etc. Hopefully we see that continue to improve over time.

    The third point has a solution in the works already (at least for crates.io). The accepted (I believe) proposal is that crates themselves act as "namespaces" and you can publish crates like bevy::render or hyper::utils that get loaded under some parent module by the compiler. Publishing crates with names containing :: would be constrained to those who maintain the parent crate (so bevy or hyper in that case).

  • source
  • parent
  • context
  • [–] 3 points 7 months ago (8 children)

    My biggest issues with rust are

    • borrow checker barely ever uses the term "borrowed" and I have to relesen it every time I pick up rust
    • async is absurdly complicated, there are so many gotchas. Streams are actual hell
    • crates are github only and have no namespacing. Java has the best solution IMO with their reverse domains for example com.github.myuser.myproject.somepackage

    It's good to know I'm not alone. But I'll never choose C/C++ over Rust. If I need speed and typing, it's Rust, no questions asked. For everything else, there's Python. I just wish Rust has better GUI frameworks...

  • source
  • [–] 7 points 7 months ago* (2 children)

    Feels empty and generic like it was written by an LLM. Why did you even ask developers to fill out a survey? You could have asked chatgpt what users thought about Rust too and saved everyone a lot of time.

  • source
  • [–] 10 points 7 months ago

    This is cool and it's nice to see some acknowledgement and self reflection.

    I actually like async Rust and I feel that they made the right decisions there. It's amazing that I can use similar constructs for a web server as well as a small embedded board. But the low level Futures stuff does get hairy. I still don't really get the relationship between Pin and Unpin, and any time I have to write a Tower Service by hand it feels arcane. Fortunately I rarely have to go down to that level.

    The tacit knowledge is interesting. Is there an ecosystem that doesn't have that to some degree? Node and Python feel even worse to me, though I admit I don't work with those as much. Still, if I ever have to look for a Node library, I get worried that I might be inadvertently installing some malware. That said, I am about to sit down with one of my juniors to start on a new Rust project, mainly because I want to help setup the initial crates (tokio, tracing, anyhow, clap, etc...). Efforts like blessed.rs are a good start. Or maybe there are some good "starter kits" using cargo-generate?

  • source
  • [–] 1 point 7 months ago (2 children)

    Rust Error Handling and Rust in General is still a big black box for me yet to be unveiled :D

    Conceptually, error handling in Rust is incredibly simple: if a function can fail, its return type is an enum of either the result of the function (in case of success) or a description of the error that happened. This enum is called Result. See:

    why do i need crates for error handling?

    You don't. You can 100% handle errors without any additional dependencies, and probably you should be doing that in the beginning. The crates simply add a little bit of syntactic sugar to simplify some boilerplate that you'll have to start writing as soon as your error handling gets sufficiently complex.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago

    Whenever you make a String you're saying that you need a string that can grow or shrink, and all the extra code required to make that work. Because it can grow or shrink it can't be stored on the (fast and efficient) stack, instead we need to ask the OS for some space on the heap, which is slow but usually has extra space around it so it can grow if needed. The OS gives back some heap space, which we can then use as a buffer to store the contents of the string.

    If you just need to use the contents of a string you can accept a &str instead. A &str is really just a reference to an existing buffer (which can be either on the stack or in the heap), so if the buffer the user passes in is on the stack then we can avoid that whole 'asking the OS for heap space' part, and if it's on the heap then we can use the existing buffer on the heap at no extra cost. Compare this to taking a &String which is basically saying 'this string must be on the heap in case it grows or shrinks, but because it's an immutable reference I promise I won't grow or shrink it' which is a bit silly.

  • source
  • parent
  • context
  • [–] [S] 1 point 7 months ago (3 children)

    Hello and Thank You :D Rust really intrigues me so i really want to explore more about Rust

    cargo clippy I'll look for Clippy

    These comments should be doc-comments (///) so that cargo doc picks them up. I see, i guess i skimmed the Rust Docs :D

    but in general you might be interested in crates thiserror and anyhow that simplify error handling. Still, Rust Error Handling and Rust in General is still a big black box for me yet to be unveiled :D, why do i need crates for error handling? But I'll look into it. Still can't quite grasp the concept of Rust

    Duration::from_mins(1) would be much more readable. Nice info, never knew this existed before, because i found it in some tutorial that timeout need something in Duration.

    You should almost never panic. Your function already returns a Result<>, so you should be using that for error handling. Still figuring how to handle error, but just like what the others say, panic should never occurred, and always return the error

    Not Rust specific, but usually I recommend to handle errors first, and return from the function early. This way you reduce cognitive load on the reader, and reduce nesting of if-blocks. That's actually correct, thank you for your input, i always ended with nasty nested if before because of this. Never thought about it before XD

    Thank you for your input. I'll refactor my code

  • source
  • parent
  • context
  • [–] [S] 1 point 7 months ago

    To Panic or not to Panic Thank you for your pointer. I just remember this from the docs. So basically, the general rule is only to use panic when something bad really happened, and my program cannot continue right? otherwise always return the error?

    Really panics should only be used when the situation should never occur and if it does that indicates a bug in the program

    I'll rethink the use of panic in my code

    would this section suffice? https://doc.rust-lang.org/book/ch09-00-error-handling.html

  • source
  • parent
  • context
  • [–] [S] 4 points 7 months ago (1 child)

    First, you should almost never take in a &String as a function argument. This basically means you have a reference to a owned object. It forces an allocation of everything passed into the function only to take a reference of it. It excludes types that are simply &strs forcing the caller to convert them to a full String - which involves an allocation. The function should just taking in a &str as it is cheap to convert a String to a &str (cheaper to use than a &String as well as &String have a double redirection).

    I think i need to explore more about pointer and reference? its still a new concept for me :D, so i just throw everything with &String without a strong understanding about the things it does in the background. Thank you for pointing that out.

    Second. String/&str are not the write types for paths. Those would be PathBuf and &Path which both work like String and &str (so all the above applies to these as well). These are generally better to use as paths in most OSs dont have to be unicode. Which means there are files (though very rarely) which cannot be represented as a String. This is why File::open takes in a AsRef which your function can also.

    What i learned from this is that a misconception of the parameter input. Instead of using String, i have to treat it as PathBuf?, I'll check it out later

    Lastly. I would not conflate opening a file with parsing it. These should be two different functions. This makes the code a bit more flexible - you can get the file to parse from other sources. One big advantage to this would be for testing where you can just have the test data as strings in the test. It also makes the returned error type simpler as one function can deal with io errors and the other with parsing errors. And in this case you can just parse the file directly from the internet request rather than saving it to a file first (though there are other reasons you may or may not want to do this).

    I do agree with this statement, I'll refactor my code to seperate the read and the parse logic

    Thank you Nous.

    PS: How do we tag other users? XD

  • source
  • parent
  • context
  • [–] [S] 1 point 7 months ago

    Box instead of String

    I need to explore more about this. I really have no idea about this

    Your parsing code looks both unrobust (potentially fragile hard-coded assumptions) and unnecessarily complex. Something much simpler can probably be done with some trivial regex usage.

    My first approach is using regex, but it seems like overkill? because the data from https://standards-oui.ieee.org/oui/oui.txt is somehow already structured.

    But i'll try the regex approach later.

    Thank you :D

  • source
  • parent
  • context
  • [–] [S] 1 point 7 months ago

    This is a IMO horribly hangup from languages that require you to declare something before you can use it. You don’t need to do that in rust. So put your functions in order that makes sense to read them from top to bottom.

    Hello, nous.

    Thank you for your feedback. I just know today that in rust, you can do this. I do agree with you about how to order things so it can convey more meaning to the reader. I'll keep that in mind in my next iterations.

    Thank you

  • source
  • parent
  • context
  • [–] 5 points 7 months ago (4 children)

    Welcome to Rust, I hope you enjoyed learning and using it :)

    One major advice would be to run cargo clippy, which gives a lot of helpful hints. Apart from that I also have some feedback.

        40	struct VendorOuiData {
        41	    vendor_organization: String, // Vendor Organization
    

    These comments should be doc-comments (///) so that cargo doc picks them up.

        49	fn fetch_oui_database(url_string: &String) -> Result<String, Box<dyn std::error::Error>> {
    

    Not saying that your return type is bad, but in general you might be interested in crates thiserror and anyhow that simplify error handling.

        51	        .timeout(Duration::new(60, 0))
    

    Duration::from_mins(1) would be much more readable.

        66	                panic!("{}", err);
    

    You should almost never panic. Your function already returns a Result<>, so you should be using that for error handling.

        70	    } else {
        71	        // HTTP Status is not 200
    

    Not Rust specific, but usually I recommend to handle errors first, and return from the function early. This way you reduce cognitive load on the reader, and reduce nesting of if-blocks.

       150	                let mut parts = line.splitn(2, '\t');
    

    There's a convenient method to split in two substrings that you could have used:

    let (mac_address, vendor_organization) = line.split_once('\t').unwrap_or(("", ""));
    
       166	                vendor_oui_data.vendor_address += line
       167	                    .trim()
       168	                    .split(' ')
       169	                    .filter(|s| !s.is_empty())
       170	                    .collect::<Vec<_>>()
       171	                    .join(" ")
       172	                    .as_str();
    

    I would probably write a regular expression that replaces all contiguous whitespace with a single space instead.

       173	                vendor_oui_data.vendor_address.push('\n');
    

    Aren't you trimming this new line off in line 181?

       181	        vendor_oui_data.vendor_address = vendor_oui_data.vendor_address.trim().to_string();
    

    This is somewhat inefficient, since you'll be allocating and copying your string here.

  • source
  • view more: ‹ prev next ›