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