diff --git a/ch10/traits/Cargo.lock b/ch10/traits/Cargo.lock new file mode 100644 index 0000000..0b7d36b --- /dev/null +++ b/ch10/traits/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "traits" +version = "0.1.0" diff --git a/ch10/traits/Cargo.toml b/ch10/traits/Cargo.toml new file mode 100644 index 0000000..a9f9604 --- /dev/null +++ b/ch10/traits/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "traits" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/ch10/traits/src/main.rs b/ch10/traits/src/main.rs new file mode 100644 index 0000000..770cb46 --- /dev/null +++ b/ch10/traits/src/main.rs @@ -0,0 +1,126 @@ +// 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 + +// 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}"); +} + +// fn notify(item1: &T, item2: &T) {} +fn notify(item: &(impl Summary + std::fmt::Display)) {} +fn notify2(item: &T) {} + +fn some_function(t: &T, u: &U) -> i32 +where + // Similar to haskell :) + T: std::fmt::Display + Clone, + U: Clone + std::fmt::Debug, +{ + 2 +} + +// impl 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 +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. + +// Stopped here pre red river gorge: +// https://rust-book.cs.brown.edu/ch10-03-lifetime-syntax.html#lifetime-elision