interfaces: refactor
This commit is contained in:
36
interfaces/01-methods/book.go
Normal file
36
interfaces/01-methods/book.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type book struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b book) print() {
|
||||||
|
// b is a copy of the original `book` value here.
|
||||||
|
fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// + you can use the same method names among different types.
|
||||||
|
// + you don't need to type `printGame`, it's just: `print`.
|
||||||
|
//
|
||||||
|
// func (b book) printBook() {
|
||||||
|
// // b is a copy of the original `book` value here.
|
||||||
|
// fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// b is a copy of the original `book` value here.
|
||||||
|
//
|
||||||
|
// func printBook(b book) {
|
||||||
|
// fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
// }
|
36
interfaces/01-methods/game.go
Normal file
36
interfaces/01-methods/game.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g game) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PREVIOUS CODE:
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// you can use same method name among different types.
|
||||||
|
// you don't need to type `printGame`, it's just: `print`.
|
||||||
|
//
|
||||||
|
// func (g game) printGame() {
|
||||||
|
// fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// you cannot use the same function name within the same package.
|
||||||
|
//
|
||||||
|
// func printGame(g game) {
|
||||||
|
// fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
// }
|
46
interfaces/01-methods/main.go
Normal file
46
interfaces/01-methods/main.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mobydick := book{
|
||||||
|
title: "moby dick",
|
||||||
|
price: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
minecraft := game{
|
||||||
|
title: "minecraft",
|
||||||
|
price: 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
tetris := game{
|
||||||
|
title: "tetris",
|
||||||
|
price: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #4: method expressions
|
||||||
|
// methods are just functions that receive a value of a type.
|
||||||
|
game.print(minecraft) // sends `minecraft` value to `game.print`
|
||||||
|
game.print(tetris) // sends `tetris` value to `game.print`
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// #3
|
||||||
|
mobydick.print() // sends `mobydick` value to `book.print`
|
||||||
|
minecraft.print() // sends `minecraft` value to `game.print`
|
||||||
|
tetris.print() // sends `tetris` value to `game.print`
|
||||||
|
|
||||||
|
// #2
|
||||||
|
// mobydick.printBook()
|
||||||
|
// minecraft.printGame()
|
||||||
|
|
||||||
|
// #1
|
||||||
|
// printBook(mobydick)
|
||||||
|
// printGame(minecraft)
|
||||||
|
}
|
20
interfaces/02-receivers/book.go
Normal file
20
interfaces/02-receivers/book.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type book struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b book) print() {
|
||||||
|
// b is a copy of the original `book` value here.
|
||||||
|
fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
}
|
34
interfaces/02-receivers/game.go
Normal file
34
interfaces/02-receivers/game.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *game) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// + discount gets a copy of `*game`.
|
||||||
|
// + discount can update the original `game` through the game pointer.
|
||||||
|
// + it's better to use the same receiver type: `*game` for all methods.
|
||||||
|
func (g *game) discount(ratio float64) {
|
||||||
|
g.price *= (1 - ratio)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PREVIOUS CODE:
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// + `g` is a copy: `discount` cannot change the original `g`.
|
||||||
|
// func (g game) discount(ratio float64) {
|
||||||
|
// g.price *= (1 - ratio)
|
||||||
|
// }
|
28
interfaces/02-receivers/list.go
Normal file
28
interfaces/02-receivers/list.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// + you can attach methods to any concrete type.
|
||||||
|
// + rule: you need to declare a new type in the same package.
|
||||||
|
type list []game
|
||||||
|
|
||||||
|
func (l list) print() {
|
||||||
|
// `list` acts like a `[]game`
|
||||||
|
if len(l) == 0 {
|
||||||
|
fmt.Println("Sorry. Our store is closed. We're waiting for the delivery 🚚.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("My Store:\n")
|
||||||
|
fmt.Printf("---------\n")
|
||||||
|
for _, it := range l {
|
||||||
|
it.print()
|
||||||
|
}
|
||||||
|
}
|
27
interfaces/02-receivers/main.go
Normal file
27
interfaces/02-receivers/main.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
// mobydick = book{title: "moby dick", price: 10}
|
||||||
|
minecraft = game{title: "minecraft", price: 20}
|
||||||
|
tetris = game{title: "tetris", price: 5}
|
||||||
|
)
|
||||||
|
|
||||||
|
var items []game
|
||||||
|
items = append(items, minecraft, tetris)
|
||||||
|
|
||||||
|
// you can attach methods to a compatible type on the fly:
|
||||||
|
my := list([]game{minecraft, tetris})
|
||||||
|
|
||||||
|
// you can call methods even on a nil value
|
||||||
|
// my = nil
|
||||||
|
|
||||||
|
my.print() // or: list.print(items)
|
||||||
|
}
|
20
interfaces/03-interfaces/book.go
Normal file
20
interfaces/03-interfaces/book.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type book struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b book) print() {
|
||||||
|
// b is a copy of the original `book` value here.
|
||||||
|
fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
}
|
34
interfaces/03-interfaces/game.go
Normal file
34
interfaces/03-interfaces/game.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *game) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// + discount gets a copy of `*game`.
|
||||||
|
// + discount can update the original `game` through the game pointer.
|
||||||
|
// + it's better to use the same receiver type: `*game` for all methods.
|
||||||
|
func (g *game) discount(ratio float64) {
|
||||||
|
g.price *= (1 - ratio)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PREVIOUS CODE:
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// + `g` is a copy: `discount` cannot change the original `g`.
|
||||||
|
// func (g game) discount(ratio float64) {
|
||||||
|
// g.price *= (1 - ratio)
|
||||||
|
// }
|
33
interfaces/03-interfaces/list.go
Normal file
33
interfaces/03-interfaces/list.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type printer interface {
|
||||||
|
print()
|
||||||
|
}
|
||||||
|
|
||||||
|
type list []printer
|
||||||
|
|
||||||
|
func (l list) print() {
|
||||||
|
if len(l) == 0 {
|
||||||
|
fmt.Println("Sorry. Our store is closed. We're waiting for the delivery 🚚.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("My Store:\n")
|
||||||
|
fmt.Printf("---------\n")
|
||||||
|
for _, it := range l {
|
||||||
|
it.print()
|
||||||
|
|
||||||
|
// you cannot access to the discount method of the game type.
|
||||||
|
// `it` is a printer not a game.
|
||||||
|
// it.discount(.5)
|
||||||
|
}
|
||||||
|
}
|
52
interfaces/03-interfaces/main.go
Normal file
52
interfaces/03-interfaces/main.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
mobydick = book{title: "moby dick", price: 10}
|
||||||
|
minecraft = game{title: "minecraft", price: 20}
|
||||||
|
tetris = game{title: "tetris", price: 5}
|
||||||
|
rubik = puzzle{title: "rubik's cube", price: 5}
|
||||||
|
)
|
||||||
|
|
||||||
|
var store list
|
||||||
|
|
||||||
|
store = append(store, &minecraft, &tetris, mobydick, rubik)
|
||||||
|
|
||||||
|
tetris.discount(.8)
|
||||||
|
// printer(tetris).discount(.8)
|
||||||
|
|
||||||
|
store.print()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var my list
|
||||||
|
|
||||||
|
// + only the `*game` have methods.
|
||||||
|
// + `game` doesn't have any methods.
|
||||||
|
// + `item` interface couldn't be satisfied with a `game` value.
|
||||||
|
// + it can only be satisfied with a `*game` value.
|
||||||
|
// my = my.add(minecraft)
|
||||||
|
my = append(my, &minecraft)
|
||||||
|
my = append(my, &tetris)
|
||||||
|
my = append(my, &mobydick)
|
||||||
|
|
||||||
|
// interface value stores a pointer to minecraft
|
||||||
|
minecraft.discount(.5)
|
||||||
|
my.list()
|
||||||
|
|
||||||
|
my.discount(.5)
|
||||||
|
my.list()
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ! cannot add mobydick to the store: it's a book type, not a game type.
|
||||||
|
// interfaces to the rescue!
|
||||||
|
// mobydick := book{title: "moby dick", price: 10}
|
||||||
|
// my.add(&mobydick)
|
||||||
|
// ----------------------------------------------------------------
|
19
interfaces/03-interfaces/puzzle.go
Normal file
19
interfaces/03-interfaces/puzzle.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type puzzle struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p puzzle) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f \n", p.title, p.price)
|
||||||
|
}
|
24
interfaces/04-interfaces/book.go
Normal file
24
interfaces/04-interfaces/book.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type book struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b book) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f \n", b.title, b.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
func (b book) total() float64 {
|
||||||
|
return b.price
|
||||||
|
}
|
28
interfaces/04-interfaces/game.go
Normal file
28
interfaces/04-interfaces/game.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
title string
|
||||||
|
price float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *game) print() {
|
||||||
|
fmt.Printf("%-15s: $%.2f\n", g.title, g.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *game) discount(ratio float64) {
|
||||||
|
g.price *= (1 - ratio)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
func (g *game) total() float64 {
|
||||||
|
return g.price
|
||||||
|
}
|
71
interfaces/04-interfaces/list.go
Normal file
71
interfaces/04-interfaces/list.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
type printer interface {
|
||||||
|
print()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
type pricer interface {
|
||||||
|
total() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
// interface embedding
|
||||||
|
type item interface {
|
||||||
|
printer
|
||||||
|
pricer
|
||||||
|
}
|
||||||
|
|
||||||
|
// a slice of item interface values
|
||||||
|
type list []item
|
||||||
|
|
||||||
|
func (l list) list() {
|
||||||
|
// `list` acts like a `[]game`
|
||||||
|
if len(l) == 0 {
|
||||||
|
fmt.Println("Sorry. Our store is closed. We're waiting for the delivery 🚚.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("My Store:\n")
|
||||||
|
fmt.Printf("---------\n")
|
||||||
|
for _, it := range l {
|
||||||
|
it.print()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
fmt.Printf("\nGROSS: $%.2f\n", l.total())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
func (l list) total() (gross float64) {
|
||||||
|
for _, it := range l {
|
||||||
|
gross += it.total()
|
||||||
|
}
|
||||||
|
return gross
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: NEW
|
||||||
|
func (l list) discount(ratio float64) {
|
||||||
|
type discounter interface {
|
||||||
|
discount(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, it := range l {
|
||||||
|
dit, ok := it.(discounter)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dit.discount(ratio)
|
||||||
|
}
|
||||||
|
}
|
35
interfaces/04-interfaces/main.go
Normal file
35
interfaces/04-interfaces/main.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
minecraft = game{title: "minecraft", price: 20}
|
||||||
|
tetris = game{title: "tetris", price: 5}
|
||||||
|
mobydick = book{title: "moby dick", price: 10}
|
||||||
|
)
|
||||||
|
|
||||||
|
var my list
|
||||||
|
// my.list() // nil receiver is a valid value
|
||||||
|
|
||||||
|
// + only the `*game` have methods.
|
||||||
|
// + `game` doesn't have any methods.
|
||||||
|
// + `item` interface couldn't be satisfied with a `game` value.
|
||||||
|
// + it can only be satisfied with a `*game` value.
|
||||||
|
// my = my.add(minecraft)
|
||||||
|
my = append(my, &minecraft)
|
||||||
|
my = append(my, &tetris)
|
||||||
|
my = append(my, &mobydick)
|
||||||
|
|
||||||
|
// interface value stores a pointer to minecraft
|
||||||
|
minecraft.discount(.5)
|
||||||
|
my.list()
|
||||||
|
|
||||||
|
my.discount(.5)
|
||||||
|
my.list()
|
||||||
|
}
|
36
interfaces/05-log-parser/01-methods/changes.md
Normal file
36
interfaces/05-log-parser/01-methods/changes.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Problem
|
||||||
|
|
||||||
|
## All these functions operate on a *parser value:
|
||||||
|
+ `main.go`:
|
||||||
|
+ `summarize(*p parser)`
|
||||||
|
+ `parser.go`:
|
||||||
|
+ `func parse(p *parser, line string) (r result)`
|
||||||
|
+ `func update(p *parser, r result)`
|
||||||
|
+ `func err(p *parser) error`
|
||||||
|
|
||||||
|
## What is an object in Go?
|
||||||
|
+ Object = A value of a type : `&parser{}` is an object.
|
||||||
|
+ `type parser struct` is the definition (class/blueprint) of the object.
|
||||||
|
|
||||||
|
### Methods are behaviors of objects:
|
||||||
|
+ Parser needs to parse, update (analyse) the parsings, and report an error if any.
|
||||||
|
+ Parser also needs to summarize the results.
|
||||||
|
+ So, all these functions belong to a parser object.
|
||||||
|
|
||||||
|
# Solution
|
||||||
|
|
||||||
|
+ Attach the functions to the parser using methods.
|
||||||
|
+ Methods are the behavior of the parser.
|
||||||
|
+ Keep the methods that belong to a single type in the same file.
|
||||||
|
|
||||||
|
1. Move the `summarize` into `parser.go`.
|
||||||
|
2. `parser.go`: Use methods.
|
||||||
|
3. `main()` : Use methods of the `parser`.
|
||||||
|
|
||||||
|
# Convince
|
||||||
|
|
||||||
|
+ `p.` shows the fields and methods belong to the `parser`.
|
||||||
|
+ `p.` selects a method from the method set of the `parser`.
|
||||||
|
+ `p.method` sends the `p` as the first parameter to the method.
|
||||||
|
+ `p` is the receiver: `*pointer`. It's a pointer receiver.
|
||||||
|
+ Receiver is copied to the method.
|
16
interfaces/05-log-parser/01-methods/log.txt
Normal file
16
interfaces/05-log-parser/01-methods/log.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 15
|
||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 20
|
||||||
|
learngoprogramming.com 5
|
||||||
|
golang.org 40
|
||||||
|
golang.org 20
|
||||||
|
golang.org 45
|
||||||
|
golang.org 15
|
||||||
|
blog.golang.org 60
|
||||||
|
blog.golang.org 30
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 65
|
||||||
|
blog.golang.org 15
|
||||||
|
inanc.io 30
|
||||||
|
inanc.io 70
|
16
interfaces/05-log-parser/01-methods/log_err_missing.txt
Normal file
16
interfaces/05-log-parser/01-methods/log_err_missing.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 15
|
||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 20
|
||||||
|
learngoprogramming.com
|
||||||
|
golang.org 40
|
||||||
|
golang.org 20
|
||||||
|
golang.org 45
|
||||||
|
golang.org 15
|
||||||
|
blog.golang.org 60
|
||||||
|
blog.golang.org 30
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 65
|
||||||
|
blog.golang.org 15
|
||||||
|
inanc.io 30
|
||||||
|
inanc.io 70
|
16
interfaces/05-log-parser/01-methods/log_err_negative.txt
Normal file
16
interfaces/05-log-parser/01-methods/log_err_negative.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 15
|
||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 20
|
||||||
|
learngoprogramming.com 5
|
||||||
|
golang.org 40
|
||||||
|
golang.org 20
|
||||||
|
golang.org -50
|
||||||
|
golang.org 15
|
||||||
|
blog.golang.org 60
|
||||||
|
blog.golang.org 30
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 65
|
||||||
|
blog.golang.org 15
|
||||||
|
inanc.io 30
|
||||||
|
inanc.io 70
|
16
interfaces/05-log-parser/01-methods/log_err_str.txt
Normal file
16
interfaces/05-log-parser/01-methods/log_err_str.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 15
|
||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 20
|
||||||
|
learngoprogramming.com 5
|
||||||
|
golang.org FORTY
|
||||||
|
golang.org 20
|
||||||
|
golang.org 45
|
||||||
|
golang.org 15
|
||||||
|
blog.golang.org 60
|
||||||
|
blog.golang.org 30
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 65
|
||||||
|
blog.golang.org 15
|
||||||
|
inanc.io 30
|
||||||
|
inanc.io 70
|
39
interfaces/05-log-parser/01-methods/main.go
Normal file
39
interfaces/05-log-parser/01-methods/main.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
p := newParser()
|
||||||
|
|
||||||
|
fmt.Printf("%T\n", (*parser).parse)
|
||||||
|
return
|
||||||
|
|
||||||
|
in := bufio.NewScanner(os.Stdin)
|
||||||
|
for in.Scan() {
|
||||||
|
parsed := p.parse(in.Text())
|
||||||
|
p.update(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.summarize()
|
||||||
|
dumpErrs([]error{in.Err(), p.err()})
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpErrs together to simplify multiple error handling
|
||||||
|
func dumpErrs(errs []error) {
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("> Err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
interfaces/05-log-parser/01-methods/parser.go
Normal file
100
interfaces/05-log-parser/01-methods/parser.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// For more tutorials: https://blog.learngoprogramming.com
|
||||||
|
//
|
||||||
|
// Copyright © 2018 Inanc Gumus
|
||||||
|
// Learn Go Programming Course
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
//
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// result stores details about a log line
|
||||||
|
type result struct {
|
||||||
|
domain string
|
||||||
|
visits int
|
||||||
|
// add more metrics when needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// parser keep tracks of the parsing
|
||||||
|
type parser struct {
|
||||||
|
sum map[string]result // metrics per domain
|
||||||
|
domains []string // unique domain names
|
||||||
|
total int // total visits for all domains
|
||||||
|
lines int // number of parsed lines (for the error messages)
|
||||||
|
lerr error // the last error occurred
|
||||||
|
}
|
||||||
|
|
||||||
|
// newParser creates and returns a new parser
|
||||||
|
func newParser() *parser {
|
||||||
|
return &parser{sum: make(map[string]result)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse result from a log line
|
||||||
|
func (p *parser) parse(line string) (r result) {
|
||||||
|
if p.lerr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.lines++
|
||||||
|
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) != 2 {
|
||||||
|
p.lerr = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
r.domain = fields[0]
|
||||||
|
r.visits, err = strconv.Atoi(fields[1])
|
||||||
|
|
||||||
|
if r.visits < 0 || err != nil {
|
||||||
|
p.lerr = fmt.Errorf("wrong input: %q (line #%d)", fields[1], p.lines)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the parsing results
|
||||||
|
func (p *parser) update(r result) {
|
||||||
|
if p.lerr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect unique domains for easy access to sum map
|
||||||
|
if _, ok := p.sum[r.domain]; !ok {
|
||||||
|
p.domains = append(p.domains, r.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep track of total visits
|
||||||
|
p.total += r.visits
|
||||||
|
|
||||||
|
// group the log lines by domain
|
||||||
|
p.sum[r.domain] = result{
|
||||||
|
domain: r.domain,
|
||||||
|
visits: r.visits + p.sum[r.domain].visits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// summarize the parsing results
|
||||||
|
func (p *parser) summarize() {
|
||||||
|
sort.Strings(p.domains)
|
||||||
|
|
||||||
|
fmt.Printf("%-30s %10s\n", "DOMAIN", "VISITS")
|
||||||
|
fmt.Println(strings.Repeat("-", 45))
|
||||||
|
|
||||||
|
for _, domain := range p.domains {
|
||||||
|
fmt.Printf("%-30s %10d\n", domain, p.sum[domain].visits)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n%-30s %10d\n", "TOTAL", p.total)
|
||||||
|
}
|
||||||
|
|
||||||
|
// err returns the last error encountered
|
||||||
|
func (p *parser) err() error {
|
||||||
|
return p.lerr
|
||||||
|
}
|
@ -11,7 +11,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/inancgumus/learngo/27-interfaces/logparser-testing/report"
|
"github.com/inancgumus/learngo/interfaces/04-log-parser/testing/report"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
@ -13,7 +13,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/inancgumus/learngo/27-interfaces/logparser-testing/report"
|
"github.com/inancgumus/learngo/interfaces/04-log-parser/testing/report"
|
||||||
)
|
)
|
||||||
|
|
||||||
// summarize prints the parsing results.
|
// summarize prints the parsing results.
|
Reference in New Issue
Block a user