The Prototype Pattern and Rust

Hello everyone,

So I have a question about using Rust and the prototype pattern. Im making a time management app and instead of using enums for Activity, i wanted to create a list of structs to represent all Activities so that a user can add more activities later...

NO:

enum Activity {
    Walk(f32), // f32 for time spent maybe?
}

YES:

struct Activity {
    title: String,
    description: String,
    time_spent: f32,
}

now I know that this is one way of doing such a thing:

#[derive(Clone)]
struct Activity {
    title: String,
    description: String,
    time_spent: f32,
}

impl Activity {
    fn new(title: String, description: String) -> Self {
        Activity {
            title,
            description,
            time_spent: 0.0_f32,
        }
    }
}

// Prototype has to impl Clone
trait Prototype: Clone {
    fn set_time_spent(&mut self, t: f32);
}

impl Prototype for Activity {
    fn set_time_spent(&mut self, t: f32) {
        self.time_spent = t;
    }
}

fn main() {
    let activity_walk = Activity::new("Walk".to_string(), "".to_string());
}

In this instance I am able to derive Clone on Activity, required to be a Prototype. However I was wondering if there was a different way to go about doing it or even a better way. I cant seem to figure out a way to go about this without partially moving parts of the Activity...

Please format your code. It is very difficult to read.

4 Likes

Another option is to separate out the common fields into a generic structure:

pub struct Activity<Details:?Sized> {
    title: String,
    time_spent: f32,
    details: Details
}

impl<T:?Sized> Activity<T> {
    // Methods that apply to all activities
    fn details(&self)->&T { &self.details }
    fn details_mut(&self)->&mut T { &mut self.details }

    // ...
}

struct Walk {
    route: String
}

fn main() {
    let mut activity_log: Vec<Box<Activity<dyn Any>>>;
    activity_log.push(Box::new( Activity {
        title: string::from("Walking"),
        time_spent: 1.5,
        details: Walk {
            route: String::from("Beach")
        }
    }
}

If your Activity is a plain structure, you can use struct update syntax for this:

#[derive(Default, Clone)]
struct Activity {
    title: String,
    description: String,
    time_spent: f32
}

fn main() {
    let activity_walk = Activity { title: String::from("Walk"), .. Activity::default() };
}
1 Like

Sorry about the lack of formatting, im not sure what it is im doing wrong exactly but shrug. In any case, i appreciate the response. What im looking for is to avoid having to hard code any activities so that users can create their own. Once an activity is created the program can then use that activity and make instances of that activity when needed. So:


  println!("you have chosen to create a new activity, type a name and a short description");

  ...
  //user types "walk, moving my feet" so:

  let user_activity = Activity::new(title:"walk",description:"moving my feet");

  &mut activity_list.push(&user_activity);
  
//heres where the trouble lies
  fn make_instance_from_activity_list(titile:String) -> Activity;

 //im trying to make an instance of walk, however if i make a new activity and fill it with ...Activity, I move ownership of my prototype - not good.

Anyways im just fishing for ideas. I havent tried yet, but i MIGHT be able to do what im thinking using "serde" and creating instances of my struct like that.
or maybe i can just use a hashmap and use its key and value for an Activity's title and description, leaving time up to the user to input

you seem to be using

> Blockquote

instead of

preformatted text:

/// ```rust         <---- edit: please note "rust" here right after three backticks
///  contents...
/// ```

:slight_smile:

1 Like

I have fixed the code blocks in your first post and also ran it through rustfmt for you (I also fixed typos that resulted in compilation errors).

Read more about how to do code blocks in this pinned post.

Running rustfmt can be done e.g. in the playground (under TOOLS in the top right corner).

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.