Rust lang series episode #10— methods and traits (#rust-series)

in #rust-series8 years ago (edited)

Hello Steemiters, here is a new rust series episode. Today, we are going to extend structs with methods and traits.

In episode #9 of this series we discussed struts. Today we will show how structs can be even more powerful.

Method definition

Method in Rust adds is some function that is connected to certain struct. Remembering Article struct from previous struct episode? If not, it doesn't matter, I'll refresh your memory.

struct Article {
    id: i32,
    upvotes: i32
}

Now suppose we wish to add some methods to it (functions that will operate with state of this struct somehow). For example method to increment upvotes counter, we will call it upvote(). It can be done via impl.

impl Article {
  fn upvote(&mut self) {
    self.upvotes += 1;
  }
}

Then we can call the method in main method.

let mut article = Article{id:0, upvotes: 0};
article.upvote();
article.upvote();
article.upvote();

println!("Article upvotes: {}", article.upvotes);

# output
Article upvotes: 3

Constructor

Cool. We have struct and method. But how about some better construction of our article instance. In Rust we can easily simulate constructor with another method. Usually this method is called new. Note that we want to always have initial upvote count to zero so we don't to offer this parameter in constructor method.

impl Article {
  fn new(id:i32) -> Article {
    Article{id: id, upvotes: 0}
  }
  fn upvote(&mut self) {
    self.upvotes += 1;
  }
}

Now we can simplify creating struct to this.

let mut article = Article::new(0);
article.upvote();
...

Note that we are using :: operator that goes to struct scope rather than dot operator that is used to self instance.

Cool! That's basically all and now we can check traits. Note that as you mutate structure you need to have &mut self. &self is reference to structure instance to access all struct fields.

Trait definition

Trait is something like standard contracts that can be implemented on a desired struct(s). Let's define Upvotable trait that will provide upvote method.

trait Upvotable {
    fn upvote(&self);
}

Like this trait doesn't do anything but it can be used.

impl Upvotable for Article {
    fn upvote(&mut self) {
        self.upvotes += 1;
    }
}

As you can see we've changed "impl Article" to impl "Upvotable for Article". Everything else remained the same. Like this it will work. For now it's enough we will see main uses cases in next episode discussing generics. But as you can already imagine now you can use defined trait to multiple structs to provide unified API. Imagine that you have another struct called Comment which can be also upvoted. Then you can implement one trait on both.

impl Upvotable for Article {
  fn upvote(&mut self) {
      self.upvotes += 1;
      println!("article upvoted");
  }
}

impl Upvotable for Comment {
  fn upvote(&mut self) {
      self.upvotes += 1;
      println!("comment upvoted");
  }
}

Postfix

That's all for today, thanks for all appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). God bless your programming skills and stay tuned for next episodes.

Meanwhile you can also check official documentation to find more about methods and traits:

#rust-series
#rust-lang
#rust

Coin Marketplace

STEEM 0.25
TRX 0.20
JST 0.038
BTC 96375.67
ETH 3572.25
USDT 1.00
SBD 3.77