Методы представляют функции, которые определены для структур или перечислений enum. Они позволяют добавить структурам и перечислениям некоторое поведение - некоторые выполняемые действия.
Формальное определение методов:
impl структура/перечисление { fn название_метода(&self){ // выполняемые действия } }
Определение методов заключается в конструкцию, которая определяется с помощью ключевого слова impl. После него идет название структуры или перечисления, для которого определяются методы.
Первый и обязательный параметр метода всегда представляет ссылку на объект структуры/перечисления, для которого запускается метод. Ссылка на объект структуры/перечисления передается с помощью &self.
Например, пусть у нас есть некоторая структура Person:
struct Person { name: String, age: u8 }
Добавим к этой структуре метод, который будет выводить ее данные на консоль. Для этого пропишем следующий код:
impl Person{ fn display(&self){ println!("Name: {} Age: {}", &self.name, &self.age); } }
После оператора impl указывается название структуры, для которой создается метод - структуры Person.
Метод называется display()
. Он имеет только один параметр - ссылку на объект структуры, который будет вызывать данный метод - &self
.
В самом методе с помощью ссылки на объект структуры мы можем обратиться к ее данным:
println!("Name: {} Age: {}", &self.name, &self.age);
Вызов метода происходит в следующем формате:
название_объекта.название_метода();
После названия объекта структуры через точку указывается имя метода, после которого в скобках перечисляются значения для параметров метода. (Для параметра &self
значение передается автоматически)
Теперь используем выше определенные структуру и метод:
fn main(){ let tom = Person{ name: "Tom".to_string(), age: 36 }; tom.display(); let bob = Person { name: "Bob".to_string(), age: 41}; bob.display(); } struct Person { name: String, age: u8 } impl Person{ fn display(&self){ println!("Name: {} Age: {}", &self.name, &self.age); } }
Консольный вывод программы:
Name: Tom Age: 36 Name: Bob Age: 41
В данном случае создается два объекта структуры Person: tom и bob. При вызове
tom.display();
В качестве ссылки на текущий объект &self
передается ссылка на объект tom, поскольку этот объект вызывает данный метод.
При этом при вызове метода для параметра &self
не надо передавать никаких значений. Поэтому при вызове метода мы не передаем ему никаких параметров.
Аналогично при вызове
bob.display();
В метод будет передаваться ссылка на объект bob, поэтому этот вызов метода выведет на консоль данные для объекта bob.
Стоит отметить, что в принципе мы здесь используем еще один метод - метод to_string()
, который преобразует значение к типу String
:
name: "Tom".to_string(),
Как и любая функция метод может принимать и другие параметры Например, добавим метод, с помощью которого один объект Person будет приветствовать другой объект Person:
fn main(){ let tom = Person { name: "Tom".to_string(), age: 36}; let bob = Person { name: "Bob".to_string(), age: 41}; tom.say_hello(&bob, 12); bob.say_hello(&tom, 19); } struct Person { name: String, age: u8 } impl Person{ fn say_hello(&self, other: &Person, hour: u8){ if hour < 16{ println!("Добрый день, {}!", other.name); } else { println!("Добрый вечер, {}!", other.name); } } fn display(&self){ println!("Name: {} Age: {}", self.name, self.age); } }
Итак, здесь добавлен метод say_hello()
, который принимает три параметра. Первый параметр традиционно - ссылка на текущий объект. Второй
параметр - other
представляет ссылку на структуру Person - человека, которого надо приветствовать. И третий параметр - hour
- текущий час. В самом методе в зависимости
от текущего часа выводим на консоль то или иное приветствие.
Поскольку метод принимает три параметра, то при вызове метода в него надо передать два значения - для второго и третьего параметра (как уже говорилось выше, для первого параметра передавать никаких значений не надо):
tom.say_hello(&bob, 12);
Консольный вывод программы:
Добрый день, Bob! Добрый вечер, Tom!
Также, как и обычные функции, метод может возвращать некоторое значение. Например, определим метод, который будет сравнивать два объекта Person по возрасту - кто старше и в зависимости от проверки возвращать некоторый результат:
fn main(){ let tom = Person { name: "Tom".to_string(), age: 36}; let bob = Person { name: "Bob".to_string(), age: 41}; let is_older = tom.is_older(&bob); if is_older{ println!("{} старше чем {}", tom.name, bob.name); } else{ println!("{} младше чем {} или одного возраста с ним", tom.name, bob.name); } } struct Person { name: String, age: u8 } impl Person{ fn is_older(&self, other: &Person) -> bool{ self.age > other.age } }
Метод сравнения на возраст называется is_older()
. В качестве параметра он принимает объект Person, с которым проводится сравнение. В качестве результата
метод возвращает значение типа bool
: true
, если возраст текущего объекта Person больше возраста объекта other, либо
false
, если возраст меньше или равен.
При вызове в метод передается значение типа Person:
let is_older = tom.is_older(&bob);
Полученный из метода результат сохраняется в переменную is_older
. Поскольку этот результат представляет тип bool
, то мы можем
использовать в конструкции if..else
и в зависимости от его значения вывести на консоль то или иное значение.
В данном случае консольный вывод будет следующим:
Tom младше чем Bob или одного возраста с ним
Если необходимо изменять текущий объект в методе, то первый параметр метода определяется как изменяемая ссылка - &mut self. Например:
fn main(){ let mut tom = Person { name: "Tom".to_string(), age: 36}; println!("До изменения: {}", tom.age); // 36 tom.change_age(22); println!("После изменения: {}", tom.age); // 22 } struct Person { name: String, age: u8 } impl Person{ fn change_age(&mut self, age: u8){ self.age = age; } }
В данном случае определен метод change_age()
, который изменяет возраст текущего объекта Person с помощью второго параметра. Соответственно первый
параметр определен как &mut self. Кроме того, переменная, которая представляет текщий объект определена с mut:
let mut tom = Person { name: "Tom".to_string(), age: 36};