Generics. Обобщенные функции и методы

Последнее обновление: 22.04.2021

Обобщенные функции

При определении обобщенных функций после названия функции в угловых скобках указываются параметры типа:

fn название_функции<T>(){
	//.......
}

Затем через параметр типа мы можем определить тип параметров или тип возвращаемого результата. Например:

fn main(){
    
	let result1 = receive(3);
	println!("{}", result1);	// 3
	
	let result2 = receive("hello");
	println!("{}", result2);	// hello
}
fn receive<T>(item: T) -> T{
	item
}

В данном случае функция receive() типизирована параметром типа T. Она имеет параметр этого типа - параметр item и возвращает результат этого типа.

А при вызове этой функции в нее можно передавать значения различных типов.

Обобщенные методы

Обобщенные методы определяются в виде:

impl<T> структура<T>{
	fn название_метода(&self){
        // выполняемые действия, которые используют параметр T
    }
}

Параметр T после ключевого слова impl указывает, что метод применяется к обобщенному типу структура<T>. Например:

struct Person<T>{

	id: T,
    name: String
}
impl<T> Person<T>{
     
    fn get_id(&self) -> &T{
        &self.id
    }
}
fn main(){
    
	let tom = Person{id:1, name: String::from("Tom")};
	let tom_id = tom.get_id();
	println!("{}", tom_id);	// 1
	
	let bob = Person{id:String::from("subadmin3"), name: String::from("Bob")};
	let bob_id = bob.get_id();
	println!("{}", bob_id);	// subadmin3
}

В данном случае структура Person является обобщенной: ее поле id имеет тип, передаваемый через параметр T.

Объявление

impl<T> Person<T>{

указывает, что реализация методов относится именно к обобщенному типу Person<T>.

Далее в методе get_id() можно использовать этот параметр T, например, для определения типа возвращаемого результата.

Реализация методов для конкретного типа

Кроме определения обобщенных методов можно определить методы для структур и перечислений, которые ограничены конкретным типом. Например:

struct Person<T>{

	id: T,
    name: String
}
impl Person<u32>{
	fn compare_id(&self, user_id: u32) -> bool{
        self.id == user_id
    }
}
fn main(){
    
	let tom = Person{id:1, name: String::from("Tom")};
	let result1 = tom.compare_id(1);
	println!("result1: {}", result1);	// result1: true
	
	let bob = Person{id:4, name: String::from("Bob")};
	let result2 = bob.compare_id(1);
	println!("result2: {}", result2);	// result2: false
}

Как и в предыдущем примере, структура Person по-прежнему обобщенная, где поле id представляет тип T. Но изменился тип, для которого определяется метод:

impl Person<u32>{

В данном случае мы говорим, что методы будут определяться только для типа Person<u32>, то есть фактически для объектов структуры Person, где параметр T будет представлять тип u32, то есть где поле id будет представлять число типа u32.

В частности, здесь определяется метод compare_id(), который принимает число и сравнивает его со значением id текущего объекта (равен или нет). Результат сравнения возвращается в качестве результата метода.

fn compare_id(&self, user_id: u32) -> bool{
	self.id == user_id
}

И поскольку метод определяется для типа Person<u32>, мы знаем, что поле id будет представлять тип u32 и мы сможем проводить все те операции, которые доступны для этого типа. Например, как в данном случае операцию сравнения.

Причем поскольку метод определяется для типа Person<u32>, мы можем вызвать у объекта структуры, в котором id представляет целое число:

let tom = Person{id:1, name: String::from("Tom")};
let result1 = tom.compare_id(1);	// все норм - id представляет целое число

Однако мы не сможем вызвать метод для структур Person, где параметр T представляет не тип u32, а какой-то другой тип, значение которого не преоразуется к типу u32. Например, в следующем случае мы получим ошибку:

let sam = Person{id: String::from("mas3"), name: String::from("Bob")};
let result3 = sam.compare_id(1);	// ! Ошибка

Здесь поле id объекта sam имеет тип String, соответственно мы имеем дело со структурой типа Person<String>, для которой НЕ существует метода compare_id, поэтому мы не можем вызвать этот метод у объекта sam.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850