Generic Data Types

TO parameterize the types of function, we need to name the type parameter. We have to declare the parameter name in the signature so that the compiler knows what that name means. Similarly, when we use a type parameter name in a function signature, we have to declare the type param before we use it.

fn largest<T>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

In Struct Definitions

We can also define structs to use a generic type parameter in one or more fields using the <> syntax.

struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}

In Enum Definition

We can define enums to hold generic data types as well. One example is the Option enum discussed earlier.

enum Option<T> {
		Some(T),
		None,
}
// Multiple generic types are supported as well
enum Result<T,E> {
		Ok(T),
    Err(E),
}

Methods

When implementing methods on a type that has generic type, we need to specify the <T> in front of the method so Rust can identify that the type in the angle brackets in that type is a generic type.

struct Example <T> {...}
impl<T> Example<T> {
    ...
}

impl Example<i32> {
// methods here will only be available when Example is of
// the i32 type
}

Traits: Defining Shared Behavior

A trait defines functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can also use trait bounds to specify that a generic type can be any type that has certain behavior. It is similar to interface in other languages but different.

Defining a Trait

A type’s behavior consists of the methods we can call on that type. Trait definitions are a way to group method signatures together to define a set of behaviors necessary to accomplish some purpose.

Here’s an example. Suppose we have different kinds of articles like NewsArticle, Tweets, etc. We are interested in building an aggregator, and we’d like to have each of the articles have a Summary trait so we can call summarize on each of them for our aggregator.

pub trait Summary {
	fn summarize(&self) -> String;

	fn view_more(&self) -> String {
			String::from("(Read more..)")
  }
}

Here, we only declare the signature because it’s up for the struct itself to implement the method. However, we could specify a default behavior if the struct using this trait does not implement such method.

Implementing a Trait on a Type