From da314f15ddbef68cc99c5ddb236147eba22321f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gytis=20Repe=C4=8Dka?= Date: Sat, 27 Oct 2018 20:17:19 +0300 Subject: [PATCH] Added struct-interface.go - in this exercise two structs Car and Truck has interface Vehicle and methods for it. Example shows how methods (functions) should be written for just specific struct or for the interface (i.e. applicable for both Car and Truck). Also explaining use of pointers as opposed to using a copy of obejct. --- struct-interface.go | 236 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 struct-interface.go diff --git a/struct-interface.go b/struct-interface.go new file mode 100644 index 0000000..d72e62f --- /dev/null +++ b/struct-interface.go @@ -0,0 +1,236 @@ +// Copyright 2018 Gytis Repečka. All rights reserved. +// Use of this source code is governed by a GNU GPL +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +// Define named structures + +type CarMake struct { + makeTitle string + countryOfOrigin string +} + +type Car struct { + make CarMake + model string + year int + started bool +} + +type Truck struct { + modelName string + year int + started bool + weight int +} + +// Interfaces +/* +Interfaces are implemented implicitly +A type implements an interface by implementing its methods. There is no explicit declaration of intent, no "implements" keyword. +Implicit interfaces decouple the definition of an interface from its implementation, which could then appear in any package without prearrangement. +Good example of interfaces: https://gobyexample.com/interfaces +*/ +// Vehicle will act as interface to Car and Truck structs. +type Vehicle interface { + FriendlyName() string + Wheels() int + Start() +} + +// Functions (methods) + +// Receiving a pointer to Car/Truck so can modify it (change started value) + +// Start method for Car +func (c *Car) Start() { + c.started = true + fmt.Printf("Car %s %s says vrooom!\n", c.make.makeTitle, c.model) +} + +// Start method for Truck +func (t *Truck) Start() { + t.started = true + fmt.Printf("Truck %s (max cargo: %d t) says br br br br!\n", t.modelName, t.weight) +} + +// Because defined only for Car and not listed as method in +// type Vehicle interface, StopCar is applicable only for Car +// but not Vehicle. +func (c *Car) StopCar() { + if c.started == true { + c.started = false + fmt.Printf("Car %s %s was stopped.\n", c.make.makeTitle, c.model) + } else { + fmt.Printf("Car %s %s is not running anyway.\n", c.make.makeTitle, c.model) + } +} + +// This method is currently implemented for Car only. There is no implementation +// for Truck therefore cannot use this method for Vehicle. +func (cr *Car) AlterName(nameAppend string) (string) { + if nameAppend != "" { + cr.model = cr.model + " " + nameAppend + } + outString := fmt.Sprintf("%s %s (%d)", cr.make.makeTitle, cr.model, cr.year) + return outString +} + +// Car has 4 wheels +func (cr Car) Wheels() int { + return 4 +} + +// Truck has 6 wheels +func (tr Truck) Wheels() int { + return 6 +} +// ...and we can then use Wheels method to know how many wheels Vehicle has. + +func (cr Car) FriendlyName() (string) { + outStarted := "not running" + if cr.started == true { + outStarted = "vuu tuuuu tuuuuu" + } + outString := fmt.Sprintf("%s %s (%d) %s", cr.make.makeTitle, cr.model, cr.year, outStarted) + return outString +} + +func (t Truck) FriendlyName() (string) { + outStarted := "not running" + if t.started == true { + outStarted = "vuu tuuuu tuuuuu" + } + outString := fmt.Sprintf("%s (%d) %s", t.modelName, t.year, outStarted) + return outString +} + +// This method is for Vehicle therefore universal (not specifically for Car or +// for Truck). Mind that inside we can use only those methods which are defined +// for Vehicle (i.e. for Car and for Truck). +func VehicleDetails(vh Vehicle) { + fmt.Printf("Vehicle %s has %d wheels.\n", vh.FriendlyName(), vh.Wheels()) +} + +// This method is intended for interface Vehicle and works for both Car and Truck +func VehicleStart(vh Vehicle) { + fmt.Println("Starting vehicle [from interface method]...") + vh.Start() +} + + +// Main function (execution point) + +func main() { + var carMakes []CarMake + newCarMake := CarMake{makeTitle: "Toyota", countryOfOrigin: "Japan"} + carMakes = append(carMakes, newCarMake) + newCarMake = CarMake{makeTitle: "Renault", countryOfOrigin: "France"} + carMakes = append(carMakes, newCarMake) + newCarMake = CarMake{"Peugeot", "France"} + carMakes = append(carMakes, newCarMake) + + var cars []Car + newCar := Car{carMakes[1], "Clio", 1994, false} + cars = append(cars, newCar) + newCar = Car{carMakes[2], "406", 1997, false} + cars = append(cars, newCar) + newCar = Car{carMakes[0], "Yaris", 2000, false} + cars = append(cars, newCar) + + fmt.Println("--------------------------") + fmt.Println("Make | Model | Country") + fmt.Println("--------------------------") + + for i:=0; i