Home » Rust Generics

Rust Generics

When we want to create the function of multiple forms, i.e., the parameters of the function can accept the multiple types of data. This can be achieved through generics. Generics are also known as ‘parametric polymorphism’ where poly is multiple, and morph is form.

There are two ways to provide the generic code:

  • Option<T>
  • Result<T, E>

Rust Generics

1. Option<T>: Rust standard library provides Option where ‘T’ is the generic data type. It provides the generic over one type.

In the above case, enum is the custom type where <T> is the generic data type. We can substitute the ‘T’ with any data type. Let’s look at this:

In the above case, we observe that ‘T’ can be of any type, i.e., i32, bool, f64 or char. But, if the type on the left-hand side and the value on the right hand side didn’t match, then the error occurs. Let’s look at this:

In the above case, type on the left-hand side is i32, and the value on the right-hand side is of type f64. Therefore, the error occurs “type mismatched”.

2. Result<T,E>: Rust standard library provides another data type Result<T,E> which is generic over two type, i.e., T &E:

Note: It is not a convention that we have to use ‘T’ and ‘E’. We can use any capital letter.

Generic functions

Generics can be used in the functions, and we place the generics in the signature of the function, where the data type of the parameters and the return value is specified.

  • When the function contains a single argument of type ‘T’.

Syntax:

The above syntax has two parts:

  • <T> : The given function is a generic over one type.
  • (x : T) : x is of type T.

When the function contains multiple arguments of the same type.

When the function contains arguments of multiple types.

Struct Definitions

Structs can also use the generic type parameter in one or more fields using <> operator.

Syntax:

In the above syntax, we declare the generic type parameter within the angular brackets just after the structure_name, and then we can use the generic type inside the struct definition.

Let’s see a simple example:

Output:

integer values : 2,3  Float values : 7.8,12.3  

In the above example, Value<T> struct is generic over one type and a and b are of the same type. We create two instances integer and float. Integer contains the values of type i32 and float contains the values of type f64.

Let’s see another simple example.

Output:

Rust Generics

In the above example, Value<T> struct is generic over one type, and a and b are of the same type. We create an instance of ‘c’. The ‘c’ contains the value of different types, i.e., i32 and f64. Therefore, the Rust compiler throws the “mismatched error”.

Enum Definitions

An enum can also use the generic data types.Rust standard library provides the Option<T> enum which holds the generic data type. The Option<T> is an enum where ‘T’ is a generic data type.

  • Option<T>

It consists of two variants, i.e., Some(T) and None.

Rust Generics

Where Some(T) holds the value of type T and None does not contain any value.

Let’s look:

In the above case, Option is an enum which is generic over one type ‘T’. It consists of two variants Some(T) and None.

  • Result<T, E>: We can create the generic of multiple types. This can be achieved through Result<T, E>.

In the above case, Result<T, E> is an enum which is generic over two types, and it consists of two variants, i.e., OK(T) and Err(E).

OK(T) holds the value of type ‘T’ while Err(E) holds the value of type ‘E’.

Method Definitions

We can implement the methods on structs and enums.

Let’s see a simple example:

Output:

p.a() is 5  

In the above example, we have implemented the method named as ‘a’ on the Program<T> that returns a reference to the data present in the variable a.

We have declared the ‘T’ after impl to specify that we are implementing the method on Program<T>.

Resolving Ambiquities

Rust compiler automatically infers the generic parameters. Let’s understand this through a simple scenario:

In the above case, we insert the integer value into the vector. Therefore, the Rust compiler got to know that the vector v has the type i32.

If we delete the second last line, then it looks like;

The above case will throw an error that “it cannot infer the type for T”.

  • We can solve the above case in two ways:

1. We can use the following annotation:

2. We can bind the generic parameter ‘T’ by using the ‘turbofish’ ::<> operator:


Next TopicRust Trait

You may also like