官术网_书友最值得收藏!

  • Mastering Rust
  • Rahul Sharma Vesa Kaihlavirta
  • 539字
  • 2021-07-02 13:35:16

Impl blocks on structs

We can add behavior to our previously defined Player struct with two functionalities: a constructor-like function that takes a name and sets default values for the remaining fields in Person, and getter and setter methods for the friend count of Person:

// struct_methods.rs

struct Player {
name: String,
iq: u8,
friends: u8
}

impl Player {
fn with_name(name: &str) -> Player {
Player {
name: name.to_string(),
iq: 100,
friends: 100
}
}

fn get_friends(&self) -> u8 {
self.friends
}

fn set_friends(&mut self, count: u8) {
self.friends = count;
}
}

fn main() {
let mut player = Player::with_name("Dave");
player.set_friends(23);
println!("{}'s friends count: {}", player.name, player.get_friends());
// another way to call instance methods.
let _ = Player::get_friends(&player);
}

We use the impl keyword, followed by the type we are implementing the methods for, followed by braces. Within braces, we can write two kinds of methods:

  • Associated methods: Methods without a self type as their first parameter. The with_name method is called an associated method because it does not have self as the first parameter. It is similar to a static method in object-oriented languages. These methods are available on the type themselves and do not need an instance of the type to invoke them. Associated methods are invoked by prefixing the method name with the struct name and double colons, like so:
      Player::with_name("Dave");
  • Instance methods: Functions that take a self value as its first argument. The self symbol here is similar to self in Python and points to the instance on which the method is implemented (here, this is Player). Therefore, the get_friends() method can only be called on already created instances of the struct:
      let player = Player::with_name("Dave");
player.get_friends();

If we were to call get_friends with the associated method syntax, that is, Player::get_friends(), the compiler gives the following error:

The error is misleading here, but it indicates that instance methods are basically associated methods with self as the first parameter and that instance.foo() is a syntax sugar. This means that we can call it like this, too: Player::get_friends(&player);. In this invocation, we pass the method an instance of Player, that is, &self is &player.

There are three variants of instance methods that we can implement on types:

  • self as the first parameter. In this case, calling this method won't allow you to use the type later.
  • &self as the first parameter. This method only provides read access to the instance of a type.
  • &mut self as the first parameter. This method provides mutable access to the instance of a type.

Our set_friends method is a &mut self method, which allows us to mutate the fields of player. We need the & operator before self, meaning that self is borrowed for the duration of the method, which is exactly what we want here. Without the ampersand, the caller would move the ownership to the method, which means that the value would get de-allocated after get_friends returns and we would not get to use our Player instance anymore. Don't worry if the terms move and borrowing does not make sense as we explain all of this in Chapter 5, Memory Management and Safety.

Now, onto implementations for enums.

主站蜘蛛池模板: 蕉岭县| 庆安县| 山东省| 华容县| 上饶市| 运城市| 乌苏市| 大宁县| 增城市| 乐东| 曲阳县| 西乌珠穆沁旗| 德阳市| 东乡| 平谷区| 霸州市| 德钦县| 仙桃市| 镇赉县| 青冈县| 博白县| 依安县| 遵义市| 桐庐县| 巴林左旗| 瓮安县| 宝坻区| 随州市| 余庆县| 苍梧县| 天等县| 尼勒克县| 会昌县| 施甸县| 奎屯市| 台湾省| 甘德县| 鄂温| 中卫市| 大竹县| 高密市|