172 lines
4.7 KiB
Rust
172 lines
4.7 KiB
Rust
// trait defines functionalitity a particular type has and
|
|
// can share with other types. Can use traits to define shared
|
|
// behavior in an abstract way. Can use trait bounds to specify
|
|
// that a generic type can be any type that has certain behavior
|
|
|
|
use std::fmt::Display;
|
|
|
|
// Like Haskell's deriving
|
|
// Except orphans aren't allowed at all
|
|
pub trait Summary {
|
|
// fn summarize(&self) -> String; // Structs must provide own implementation
|
|
fn summarize(&self) -> String {
|
|
String::from("(Read more...)")
|
|
}
|
|
}
|
|
|
|
pub struct NewsArticle {
|
|
pub headline: String,
|
|
pub location: String,
|
|
pub author: String,
|
|
pub content: String,
|
|
}
|
|
|
|
impl Summary for NewsArticle {
|
|
fn summarize(&self) -> String {
|
|
format!("{}, by {} ({})", self.headline, self.author, self.location)
|
|
}
|
|
}
|
|
|
|
pub struct Tweet {
|
|
pub username: String,
|
|
pub content: String,
|
|
pub reply: bool,
|
|
pub retweet: bool,
|
|
}
|
|
|
|
impl Summary for Tweet {
|
|
fn summarize(&self) -> String {
|
|
format!("{}: {}", self.username, self.content)
|
|
}
|
|
}
|
|
|
|
// Should use lifetime annotations when using a reference
|
|
// in a variable
|
|
struct ImportantExcerpt<'a> {
|
|
part: &'a str,
|
|
}
|
|
|
|
fn main() {
|
|
let tweet = Tweet {
|
|
username: String::from("horse_ebooks"),
|
|
content: String::from("of course, as you probably already know, people"),
|
|
reply: false,
|
|
retweet: false,
|
|
};
|
|
|
|
println!("1 new tweet: {}", tweet.summarize());
|
|
|
|
// The next lines fail as borrowing
|
|
// let r;
|
|
|
|
// {
|
|
// let x = 5;
|
|
// r = &x;
|
|
// }
|
|
|
|
// println!("r: {}", r);
|
|
|
|
let x = 5;
|
|
let r = &x;
|
|
println!("r: {r}");
|
|
|
|
let string1 = String::from("abcd");
|
|
let string2 = "xyz";
|
|
|
|
// need a lifetime reference for situations like this
|
|
// &i32: a regular reference
|
|
// &'a i32: a reference with an explicit lifetime
|
|
// &'a mut i32: a mutable reference with an explicit lifetime
|
|
let result = longest(string1.as_str(), string2);
|
|
println!("The longest string is {result}");
|
|
|
|
let string1 = String::from("long string is long");
|
|
// let result;
|
|
|
|
{
|
|
let string2 = String::from("xyz");
|
|
let result = longest(string1.as_str(), string2.as_str());
|
|
// result = longest(string1.as_str(), string2.as_str());
|
|
println!("The longest string is {result}");
|
|
}
|
|
|
|
// println!("The longest string is {result}");
|
|
|
|
// the static lifetime
|
|
// Can life for the duration of the program
|
|
let s: &'static str = "I have a static lifetime";
|
|
}
|
|
|
|
// fn notify<T: Summary>(item1: &T, item2: &T) {}
|
|
fn notify(item: &(impl Summary + std::fmt::Display)) {}
|
|
fn notify2<T: Summary + std::fmt::Display>(item: &T) {}
|
|
|
|
fn some_function<T, U>(t: &T, u: &U) -> i32
|
|
where
|
|
// Similar to haskell :)
|
|
T: std::fmt::Display + Clone,
|
|
U: Clone + std::fmt::Debug,
|
|
{
|
|
2
|
|
}
|
|
|
|
// impl<T: Display> ToString for T {}
|
|
|
|
// <'a> and 'a dispersed in the function parameters are
|
|
// lifetime annotations. Lifetimes annotations are needed because
|
|
// Rust can't tell whether the reference being returned refers to x or y
|
|
// Feels like a similar vibe to Haskell `forall a`.
|
|
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
|
if x.len() > y.len() {
|
|
x
|
|
} else {
|
|
y
|
|
}
|
|
}
|
|
|
|
// lifetime elision rules. Some functions that have common patterns
|
|
// with references passed as a parameter have lifetime annotations
|
|
// passed implicitly due to soooooo many functions having this
|
|
// lifetime annotation pattern used.
|
|
//
|
|
// Lifetimes on function/method parameters called input lifetimes.
|
|
// Lifetimes on return values output lifetimes
|
|
//
|
|
// 3 Rules for lifetime functions
|
|
// 1: Compiler assigns different lifetime parameter to each lifetime
|
|
// in each input type
|
|
// fn foo(x: &i32) becomes fn foo<'a>(x: &'a i32)
|
|
// fn foo(x: &i32, y: &i32) becomes fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
|
|
// fn foo(x: &ImportantExcerpt) becomes fn foo<'a, 'b>(x: &'a ImportantExcerpt<'b>)
|
|
// 2: If exactly one input lifetime paramter, lifetime applied to all output
|
|
// lifetime parameters
|
|
// 3: If multiple input lifetime parameters, but one of them is &self or &mut self,
|
|
// lifetime of self assigned to all output lifetime parameters
|
|
|
|
// Lifetime annotations in method definitions
|
|
|
|
impl<'a> ImportantExcerpt<'a> {
|
|
fn level(&self) -> i32 {
|
|
3
|
|
}
|
|
|
|
// example of third lifetime elision rule
|
|
fn announce_and_return_part(&self, announcement: &str) -> &str {
|
|
println!("Attention Please: {announcement}");
|
|
self.part
|
|
}
|
|
}
|
|
|
|
// Generic Type Paramters, trait bounds, and lifetimes together
|
|
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
|
|
where
|
|
T: Display,
|
|
{
|
|
println!("Announcement!: {ann}");
|
|
if x.len() > y.len() {
|
|
x
|
|
} else {
|
|
y
|
|
}
|
|
}
|