// 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