Generics 101

For those coming from the likes of C++ and C#, generics will be nothing new to you. It is typically represented as T. It is used in the same way as a standard type. As T doesn't actually have a type, it's known a polymorphic parameter.

There's a simple rule regarding generic types.

The types have to match—if we define T as being f64 and attempt to assign a String to it, the compiler will fail to build that code.

While T is also (probably) the most commonly used letter for a generic type, in reality you can have any letter, or even words.

For example, this is perfectly acceptable code:

enum Result<Y, N> 
{ 
    Ok(Y), 
    Err(N), 
} 

Y and N do not need to be the same type either; therefore, Y could be a String and N a bool.

In practice, the following shows how the generic type works. Option is provided as part of the standard library:

enum Option<T> 
{ 
    Some_Type(T), 
    None 
} 
let varname: Option<f32> = Some_Type(3.1416f32); 

Generics also provide another useful facility: they allow for the production of generic functions.

Generic functions—the functions that you can throw anything at! A standard function may look like this:

fn defined_type_fn(x: i32) 
{ 
    // do something with x 
} 
The example code for this section can be found in 09/multiply_generic_return_t.

The parameter being passed in is an i32 and is called x. If we attempt to pass in a float, bool, string, or any other type that is not an i32, the compiler will fail the build as the types don't match.

The generic function looks very similar:

fn generic_type_fn<T>(x: T) 
{ 
    // do something with x 
} 

In style, this is very similar to how a generic method is written in C#:

void generic_type_method<T>(T x) 
{ 
    // do something 
} 

This can be extended to take multiple parameters with the same type:

fn generic_type_fn<T>(x: T, y: T) 
{ 
    // do something 
} 

Or with multiple types and parameters:

fn generic_types_fn<T, U, V>(x: T, y: U, z: V) 
{ 
    // do something 
} 

Finally, we can use a generic as a return type. Recall that a standard function returns a value like this:

fn multiply(a: i32, b: i32) -> i32 
{ 
    return a * b; 
} 

The generic return would be as follows:

fn multiply_generic<T>(a: T, b: T) -> T 
{ 
    return a * b; 
} 

This will only work for simplesome types; you cannot multiply string types, though you can concatenate them—this means you add one string to another. The problem though is we cannot do this... yet.

When we attempt to build this, an error is generated:

Binary operation '*' cannot be applied to type 'T'; an implementation of 'std::ops::Mul' might be missing for 'T'

Let's see if we can break this down a bit to see why we're getting the error.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset