(back to exercise)
struct Library {
books: Vec<Book>,
}
struct Book {
title: String,
year: u16,
}
impl Book {
// This is a constructor, used below.
fn new(title: &str, year: u16) -> Book {
Book {
title: String::from(title),
year,
}
}
}
// Implement the methods below. Notice how the `self` parameter
// changes type to indicate the method's required level of ownership
// over the object:
//
// - `&self` for shared read-only access,
// - `&mut self` for unique and mutable access,
// - `self` for unique access by value.
impl Library {
fn new() -> Library {
Library { books: Vec::new() }
}
fn len(&self) -> usize {
self.books.len()
}
fn is_empty(&self) -> bool {
self.books.is_empty()
}
fn add_book(&mut self, book: Book) {
self.books.push(book)
}
fn print_books(&self) {
for book in &self.books {
println!("{}, published in {}", book.title, book.year);
}
}
fn oldest_book(&self) -> Option<&Book> {
// Using a closure and a built-in method:
// self.books.iter().min_by_key(|book| book.year)
// Longer hand-written solution:
let mut oldest: Option<&Book> = None;
for book in self.books.iter() {
if oldest.is_none() || book.year < oldest.unwrap().year {
oldest = Some(book);
}
}
oldest
}
}
fn main() {
let mut library = Library::new();
println!(
"The library is empty: library.is_empty() -> {}",
library.is_empty()
);
library.add_book(Book::new("Lord of the Rings", 1954));
library.add_book(Book::new("Alice's Adventures in Wonderland", 1865));
println!(
"The library is no longer empty: library.is_empty() -> {}",
library.is_empty()
);
library.print_books();
match library.oldest_book() {
Some(book) => println!("The oldest book is {}", book.title),
None => println!("The library is empty!"),
}
println!("The library has {} books", library.len());
library.print_books();
}
#[test]
fn test_library_len() {
let mut library = Library::new();
assert_eq!(library.len(), 0);
assert!(library.is_empty());
library.add_book(Book::new("Lord of the Rings", 1954));
library.add_book(Book::new("Alice's Adventures in Wonderland", 1865));
assert_eq!(library.len(), 2);
assert!(!library.is_empty());
}
#[test]
fn test_library_is_empty() {
let mut library = Library::new();
assert!(library.is_empty());
library.add_book(Book::new("Lord of the Rings", 1954));
assert!(!library.is_empty());
}
#[test]
fn test_library_print_books() {
let mut library = Library::new();
library.add_book(Book::new("Lord of the Rings", 1954));
library.add_book(Book::new("Alice's Adventures in Wonderland", 1865));
// We could try and capture stdout, but let us just call the
// method to start with.
library.print_books();
}
#[test]
fn test_library_oldest_book() {
let mut library = Library::new();
assert!(library.oldest_book().is_none());
library.add_book(Book::new("Lord of the Rings", 1954));
assert_eq!(
library.oldest_book().map(|b| b.title.as_str()),
Some("Lord of the Rings")
);
library.add_book(Book::new("Alice's Adventures in Wonderland", 1865));
assert_eq!(
library.oldest_book().map(|b| b.title.as_str()),
Some("Alice's Adventures in Wonderland")
);
}
(back to exercise)
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Point {
x: i32,
y: i32,
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub fn magnitude(self) -> f64 {
f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()
}
pub fn dist(self, other: Point) -> f64 {
(self - other).magnitude()
}
}
impl std::ops::Add for Point {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl std::ops::Sub for Point {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
pub struct Polygon {
points: Vec<Point>,
}
impl Polygon {
pub fn new() -> Polygon {
Polygon { points: Vec::new() }
}
pub fn add_point(&mut self, point: Point) {
self.points.push(point);
}
pub fn left_most_point(&self) -> Option<Point> {
self.points.iter().min_by_key(|p| p.x).copied()
}
pub fn iter(&self) -> impl Iterator<Item = &Point> {
self.points.iter()
}
pub fn length(&self) -> f64 {
if self.points.is_empty() {
return 0.0;
}
let mut result = 0.0;
let mut last_point = self.points[0];
for point in &self.points[1..] {
result += last_point.dist(*point);
last_point = *point;
}
result += last_point.dist(self.points[0]);
result
// Alternatively, Iterator::zip() lets us iterate over the points as pairs
// but we need to pair each point with the next one, and the last point
// with the first point. The zip() iterator is finished as soon as one of
// the source iterators is finished, a neat trick is to combine Iterator::cycle
// with Iterator::skip to create the second iterator for the zip and using map
// and sum to calculate the total length.
}
}
pub struct Circle {
center: Point,
radius: i32,
}
impl Circle {
pub fn new(center: Point, radius: i32) -> Circle {
Circle { center, radius }
}
pub fn circumference(&self) -> f64 {
2.0 * std::f64::consts::PI * f64::from(self.radius)
}
pub fn dist(&self, other: &Self) -> f64 {
self.center.dist(other.center)
}
}
pub enum Shape {
Polygon(Polygon),
Circle(Circle),
}
impl From<Polygon> for Shape {
fn from(poly: Polygon) -> Self {
Shape::Polygon(poly)
}
}
impl From<Circle> for Shape {
fn from(circle: Circle) -> Self {
Shape::Circle(circle)
}
}
impl Shape {
pub fn perimeter(&self) -> f64 {
match self {
Shape::Polygon(poly) => poly.length(),
Shape::Circle(circle) => circle.circumference(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn round_two_digits(x: f64) -> f64 {
(x * 100.0).round() / 100.0
}
#[test]
fn test_point_magnitude() {
let p1 = Point::new(12, 13);
assert_eq!(round_two_digits(p1.magnitude()), 17.69);
}
#[test]
fn test_point_dist() {
let p1 = Point::new(10, 10);
let p2 = Point::new(14, 13);
assert_eq!(round_two_digits(p1.dist(p2)), 5.00);
}
#[test]
fn test_point_add() {
let p1 = Point::new(16, 16);
let p2 = p1 + Point::new(-4, 3);
assert_eq!(p2, Point::new(12, 19));
}
#[test]
fn test_polygon_left_most_point() {
let p1 = Point::new(12, 13);
let p2 = Point::new(16, 16);
let mut poly = Polygon::new();
poly.add_point(p1);
poly.add_point(p2);
assert_eq!(poly.left_most_point(), Some(p1));
}
#[test]
fn test_polygon_iter() {
let p1 = Point::new(12, 13);
let p2 = Point::new(16, 16);
let mut poly = Polygon::new();
poly.add_point(p1);
poly.add_point(p2);
let points = poly.iter().cloned().collect::<Vec<_>>();
assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);
}
#[test]
fn test_shape_perimeters() {
let mut poly = Polygon::new();
poly.add_point(Point::new(12, 13));
poly.add_point(Point::new(17, 11));
poly.add_point(Point::new(16, 16));
let shapes = vec![
Shape::from(poly),
Shape::from(Circle::new(Point::new(10, 20), 5)),
];
let perimeters = shapes
.iter()
.map(Shape::perimeter)
.map(round_two_digits)
.collect::<Vec<_>>();
assert_eq!(perimeters, vec![15.48, 31.42]);
}
}
fn main() {}