~bayindirh/introducing_go_book_examples

b0559f8bf8c80fc17eecb8c78ebe82b619d17f4b — Hakan Bayindir 2 years ago db6911f
Complete chapter 7 examples and exercises.

This commit completes chapter 7 examples and exercises. Also contains a new extracurricular example to show method overloading/overriding.
A src/chapter7/03-structs_and_methods_1.go => src/chapter7/03-structs_and_methods_1.go +21 -0
@@ 0,0 1,21 @@
package main

import ("fmt"; "math")

type Circle struct{
	xCoordinate float64
	yCoordinate float64
	radius float64
}

// Let's define a method, which calculates the are of our circle.
// It's like an in-object or in-struct function. It just lives outside.
func (circle *Circle) area() float64 {
	return circle.radius * circle.radius * math.Pi
}

func main() {
	circle := Circle{0, 0, 4}
	
	fmt.Println("The area of the circle is", circle.area())
}
\ No newline at end of file

A src/chapter7/04-structs_and_embedded_types_1.go => src/chapter7/04-structs_and_embedded_types_1.go +31 -0
@@ 0,0 1,31 @@
package main

import "fmt"

// This is a person struct. We'll embed this into something else below.
type Person struct {
	Name string
}

func (person *Person) talk() {
	fmt.Println("Hello, my name is", person.Name + ".")
}

// Let's create an Android.
type Android struct {
	// Android is a person.
	// We _inherited_ the person type into this.
	// Embed is just a fancy name.
	Person // This is called an anonymous field.
	Model string
}

func main() {
	// Let's create an Android object.
	andy := Android{}
	andy.Name = "Andy" // This comes from Person struct. 
	andy.Model = "MK-I" // This is from Android struct.

	andy.talk() // Again, methods are also inherited.	
	andy.Person.talk() // You can also reach out to the inherited object.
}
\ No newline at end of file

A src/chapter7/05-interfaces_1.go => src/chapter7/05-interfaces_1.go +54 -0
@@ 0,0 1,54 @@
package main

import ("fmt"; "math")

// This is our shape interface which carries our area function.
type Shape interface {
	area() float64
}

// Then, let's add our structs:
type Circle struct{
    xCoordinate float64
    yCoordinate float64
    
    radius float64
}

type Rectangle struct{
	xCoordinate float64
	yCoordinate float64
	
	xLength float64
	yLength float64
}

// Next, add methods for these structs.
// By implementing these methods, we also implement the interface. 
func (rectangle *Rectangle) area() float64 {
	return rectangle.xLength * rectangle.yLength
}

func (circle *Circle) area() float64 {
	return math.Pi * circle.radius * circle.radius
}

// Add a function for getting the total area of every shape.
// Note how we use the Shape type (interface).
func totalArea (shapes ...Shape) float64 {
	var totalArea float64 = 0
	
	for _, shape := range shapes {
		totalArea += shape.area()
	}
	
	return totalArea
}

func main() {
	rectangle1 := Rectangle{0, 0, 4, 4}
	circle1 := Circle{0, 0, 4}
	
	// Let's try our interface:
	fmt.Println("Total area is", totalArea(&rectangle1, &circle1))
}
\ No newline at end of file

A src/chapter7/06-interfaces_2.go => src/chapter7/06-interfaces_2.go +77 -0
@@ 0,0 1,77 @@
package main

import ("fmt"; "math")

// This is our shape interface which carries our area function.
type Shape interface {
	area() float64
}

// Then, let's add our structs:
type Circle struct{
    xCoordinate float64
    yCoordinate float64
    
    radius float64
}

type Rectangle struct{
	xCoordinate float64
	yCoordinate float64
	
	xLength float64
	yLength float64
}

// You can even create a struct which contains the interface as the field.
type MultiShape struct{
	shapes []Shape // This accepts any Struct which implement Shape interface.
}

// Next, add methods for these structs.
func (rectangle *Rectangle) area() float64 {
	return rectangle.xLength * rectangle.yLength
}

func (circle *Circle) area() float64 {
	return math.Pi * circle.radius * circle.radius
}

// Let's implement the Shape interface to MultiShape:
// By implementing an Area function, you make it compliant.
func (shape *MultiShape) area () float64 {
	var totalArea float64 = 0
	
	for _, shape := range shape.shapes {
		totalArea += shape.area()
	}
	
	return totalArea
}

// Add a function for getting the total area of every shape.
// Note how we use the Shape type (interface).
func totalArea (shapes ...Shape) float64 {
	var totalArea float64 = 0
	
	for _, shape := range shapes {
		totalArea += shape.area()
	}
	
	return totalArea
}

func main() {
	// Since we implement the interface with pointer receivers, we need to add Rectangle
	// and Circle's pointers to the slice.
	// A very detailed explanation: https://stackoverflow.com/a/40824044
	multiShape := MultiShape{
		shapes: []Shape{
					&Rectangle{0, 0, 4, 4},
					&Circle{0, 0, 4},
					},
				}

	// Let's try our interface:
	fmt.Println("Total area is", totalArea(&multiShape))
}
\ No newline at end of file

A src/chapter7/07-exercise_1.go => src/chapter7/07-exercise_1.go +74 -0
@@ 0,0 1,74 @@
package main

import ("fmt"; "math")

// This is our shape interface which carries our area function.
type Shape interface {
	area() float64
	perimeter() float64
}

// Then, let's add our structs:
type Circle struct{
    xCoordinate float64
    yCoordinate float64
    
    radius float64
}

type Rectangle struct{
	xCoordinate float64
	yCoordinate float64
	
	xLength float64
	yLength float64
}

// Next, add methods for these structs.
// By implementing these methods, we also implement the interface. 
func (rectangle *Rectangle) area() float64 {
	return rectangle.xLength * rectangle.yLength
}

func (rectangle *Rectangle) perimeter() float64 {
	return 2 * (rectangle.xLength + rectangle.yLength)
}

func (circle *Circle) area() float64 {
	return math.Pi * circle.radius * circle.radius
}

func (circle *Circle) perimeter() float64 {
	return 2 * math.Pi * circle.radius
}

// Add a function for getting the total area of every shape.
// Note how we use the Shape type (interface).
func totalArea (shapes ...Shape) float64 {
	var totalArea float64 = 0
	
	for _, shape := range shapes {
		totalArea += shape.area()
	}
	
	return totalArea
}

func totalPerimeter (shapes ...Shape) float64 {
	var totalPerimeter float64 = 0
	
	for _, shape := range shapes {
		totalPerimeter += shape.perimeter()
	}
	
	return totalPerimeter
}

func main() {
	rectangle1 := Rectangle{0, 0, 4, 4}
	circle1 := Circle{0, 0, 4}
	
	// Let's try our interface:
	fmt.Println("Total area is", totalArea(&rectangle1, &circle1))
	fmt.Println("Total perimeter is", totalPerimeter(&rectangle1, &circle1))
}
\ No newline at end of file

A src/extracurricular/02-structs_embedding_and_function_overriding.go => src/extracurricular/02-structs_embedding_and_function_overriding.go +36 -0
@@ 0,0 1,36 @@
package main

import "fmt"

// This is a person struct. We'll embed this into something else below.
type Person struct {
	Name string
}

func (person *Person) talk() {
	fmt.Println("Hello, my name is", person.Name + ".")
}

// Let's create an Android.
type Android struct {
	// Android is a person.
	// We _inherited_ the person type into this.
	// Embed is just a fancy name.
	Person // This is called an anonymous field.
	Model string
}

// You can override the methods coming from the base structures.
func (android *Android) talk() {
	fmt.Println("Hello my name is", android.Name, "and my model is", android.Model + ".")
}

func main() {
	// Let's create an Android object.
	andy := Android{}
	andy.Name = "Andy" // This comes from Person struct. 
	andy.Model = "MK-I" // This is from Android struct.

	andy.talk() // This method is overriden for Android type.
	andy.Person.talk() // You can also reach out to the inherited object.
}
\ No newline at end of file