Generic types, traits, lifetimes¶
In every language there are tools for handling duplicate concepts.
In Rust one such type is generics.
Removing duplication¶
Removing a duplication by extracting a function:
fn main() {
let list = vec![23,54,65,67]
let mut largest = list[0];
for n in list {
if n > largest {
largest = n;
}
}
println!("Largest No. {}", largest);
let list = vec![223,544,655,67]
let mut largest = list[0];
for n in list {
if n > largest {
largest = n;
}
}
println!("Largest No. {}", largest);
}
fn main() {
let list = vec![23,54,65,67];
let result = largest(&list);
println!("{}", result);
let list = vec![223,544,655,67]
let result = largest(&list);
println!("{}", result);
let list = vec!['y','t','u']
let result = largest_char(&list);
println!("{}", result);
}
fn largest(list :&[i32]) -> i32 {
let mut largest = list[0];
for n in list {
if n > largest {
largest = n;
}
}
largest
}
fn largest_char(list :&[char]) -> char {
let mut largest = list[0];
for n in list {
if n > largest {
largest = n;
}
}
largest
}
Now remove the duplication of the functions with different types:
fn main() {
let list = vec![23,54,65,67];
let result = largest(&list);
println!("{}", result);
let list = vec![223,544,655,67];
let result = largest(&list);
println!("{}", result);
let list = vec!['y','t','u'];
let result = largest_char(&list);
println!("{}", result);
}
fn largest<T:PartialOrd+Copy>(list :&[T]) -> T {
let mut largest = list[0];
for n in list {
if n > &largest {
largest = *n;
}
}
largest
}
Generics in structure definition¶
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point{x:5, y:10};
let float = Point{x:8.0, y:9.4};
println!("{:?}\n{:?}", integer, float);
}
Generics in Enum definition¶
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E)
}
#[derive(Debug)]
struct Point<T, E> {
x: T,
y: T,
}
impl <T> Point<T> {
fn x(&self) -> &T {
&self.x;
}
}
Concrete types in Generics¶
impl Point<f32> {
fn number(&self) -> f32 {
self.x
}
}
impl Point<i32> {
fn number(&self) -> i32 {
self.x
}
}
fn main() {
let n = Point{x:2.2, y: 3.14};
println!("{}", n.number());
let n = Point{x:2, y: 3};
println!("{}", n.number());
}
Performance of code using generics¶
While using generics, there is no performance impact because Rust transforms these types at the compile time.
Defining traits¶
trait Summary {
fn summarize(&self) -> String;
}
struct NewsArticle {
headline: String,
location: String,
author: String,
content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({}) \n {}", self.headline, self.author, self.location, self.content)
}
}
fn main() {
let news = NewsArticle {
headline: String::from("The title"),
location: String::from("The location"),
author: String::from("The author"),
content:String::from("The content"),
};
println!("News Article \n{}", news.summarize());
}
Default implementation¶
You can define a default implementation of a trait method, if defined in the struct, it will be overwritten.
trait Summary {
fn summarize(&self) -> String {
String::from("Default implementation");
}
}
Lifetime Annotation syntax¶
fn main() {
let s1 = "Hello";
let s2 = "Bye";
let result = longest(s1, s2);
println!("{}", result);
}
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
Will throw an error - "This function's return type contain a borrowed value, but the signature does not say wether it is borrowed from 'x' or 'y'."
fn main() {
let s1 = "Hello";
let s2 = "Bye";
let result = longest(s1, s2);
println!("{}", result);
}
fn longest<'a>(x: &'a str, y:&'a str) -> 'a str {
if x.len() > y.len() {
x
} else {
y
}
}
struct<'a> {
name: &'a String,
}
impl <'a> S <'a> {
fn fun(&self) -> &String {
self.name
}
}
fn main() {
let s = S{
name: &String::from("Name"),
}
println!("{}", s.fun());
}