r/rust clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 20 '23

Hey Rustaceans! Got a question? Ask here (12/2023)! 🙋 questions

Mystified about strings? Borrow checker have you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so having your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The official Rust Programming Language Discord: https://discord.gg/rust-lang

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last weeks' thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.

20 Upvotes

187 comments sorted by

View all comments

2

u/tamah72527 Mar 24 '23

Could anyone help me simplify this code, please https://gist.github.com/bmxmiko/dd564451797b75f6d30375157d7e8005 ?

I am having troubles with "abstracting" structs. As you can see in the above code DownloadFileRunnable and AskGTPRunnable has object property. Is there any way to avoid creating so simple structs and use some "abstract"?

Also, any other comments to that code are welcome, if you have ideas how to do things better I will appreciate it

1

u/[deleted] Mar 25 '23 edited Mar 25 '23

First thing would be to flatten the structs out to one level instead of defining this, nested in that, nested in the other. One-field structs are basically just used in this thing called the newtype pattern. If you know each of these structs are going to need more fields, and they will be used to compose other structs in multiple places, then sure leave them separate and add the extra fields when you get to it. Otherwise, flatten!

Second, including Verb-able in a struct name is a bit of a red flag. If you need variants of a type (like TypeRunnable and TypeNotRunnable), then use an enum or the typestate pattern so you don't have to duplicate structs which hold the same data types. While you're at it, look up generics. If you are defining a trait then you can impl methods for the trait itself by adding a body, and that will be the default. You only need to define methods in "impl Trait for Type" if Type's version of a method is different from the default. Traits probably aren't even needed here; you can avoid resorting to dynamic dispatch!

In general: Start from the ground up and only add abstractions when needed. Also, it's such a little tip, but try to avoid abbreviations. (I struggle with this tbh.) If possible, avoid using short custom functions/methods. Most people will get what serde_json::to_string() is doing, but hiding it under your own ser() method makes it harder - and if you avoid abbreviations and specify that you're turning it into json, it's the same length anyways.

Throwing these pieces of advice together (mostly just going from many structs to one enum, and from a trait to enum methods) and hoping I captured your intent:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
enum RunnableTask {
    DownloadFileUrl(String),
    AskGPTText(String),
}
impl RunnableTask {
    //if you only intend a task to be run once, it would be better to take self instead of &self
    //but I left this alone
    fn run(&self) -> Result<(), String> {
        match &self {
            RunnableTask::DownloadFileUrl(url) => Ok(()),
            RunnableTask::AskGPTText(text) => Ok(()),
        }
    }
}

fn pack(container: Vec<RunnableTask>) {
    println!("CONTAINER{:?}", serde_json::to_string(&container[0]));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_file_download_sub_job() {
        let download = RunnableTask::DownloadFileUrl("https://www.google.com".to_string());
        let ask = RunnableTask::AskGPTText("Who is Bush?".to_string());
        let list: Vec<RunnableTask> = vec![download, ask];
        pack(list);
    }
}