Generics are programming techniques that do not specify specific types when writing code, but then determine types when using them. It allows us to write more general and reusable code and avoid repeating similar code.
In Rust, generics are widely used in data types, functions and methods, trait and other aspects. This article will introduce in detail the related concepts and usage of generics in Rust.
Generic data types
When defining structures or enumerations, we can use generic parameters instead of specific types. This way, when using these structures or enums, we can specify specific types for them.
For example, the following is a defined using generic parametersPoint
Structure:
struct Point<T> { x: T, y: T, } let int_point = Point { x: 1, y: 2 }; let float_point = Point { x: 1.0, y: 2.0 };
In the above code, we define a name calledPoint
The structure of , which has two generic parametersx
andy
. When using this structure, we can specify a specific type for it, such asint_point
andfloat_point
Shown.
Generic functions and methods
When defining a function or method, we can also use generic parameters instead of specific types. In this way, when calling these functions or methods, we can specify specific types for them.
For example, the following is a defined using generic parameterslargest
Function:
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = list[0]; for &item in list { if item > largest { largest = item; } } largest } let numbers = vec![1, 2, 3]; let result = largest(&numbers);
In the above code, we define a name calledlargest
The function that accepts a generic parameterT
. When calling this function, we can specify a specific type for it, such asresult
Shown.
Generic trait
When defining trait, we can also use generic parameters instead of specific types. In this way, when implementing these traits, we can specify specific types for them.
For example, the following is a defined using generic parametersSummary
trait:
pub trait Summary { fn summarize<T: Display>(&self, value: T) -> String; } impl Summary for NewsArticle { fn summarize<T: Display>(&self, value: T) -> String { format!("{} - {}", , value) } }
In the above code, we define a name calledSummary
trait, it has a generic methodsummarize
. When implementing this trait, we can specify a specific type for it, such asNewsArticle
Shown.
Generic constraints
Sometimes, we need to impose some constraints on generic parameters to ensure that they meet certain conditions. In Rust, we can use the trait bound and where clauses to constrain generic parameters.
For example, thelargest
In the function, we use generic parametersT
The following constraints are implemented:
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { // ... }
In the above code<T: PartialOrd + Copy>
Partial representation: generic parametersT
Need to be implementedPartialOrd
andCopy
These two traits. In this way, when calling this function, we can only pass in types that implement these two traits.
In addition to using trait bound, we can also use the where clause to constrain generic parameters. For example, the abovelargest
Functions can also be written like this:
fn largest<T>(list: &[T]) -> T where T: PartialOrd + Copy, { // ... }
In the above codewhere T: PartialOrd + Copy
Partial representation: generic parametersT
Need to be implementedPartialOrd
andCopy
These two traits. This writing method is the same as using trait bound, except that the syntax is different. from Liu Jin, please indicate the original link when reprinting. grateful!
This is the end of this article about the detailed explanation of the use of generics in Rust. For more related Rust generic content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!