refactor: stringer interface
This commit is contained in:
		| @@ -9,43 +9,20 @@ package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type book struct { | ||||
| 	product | ||||
| 	published interface{} | ||||
| 	published timestamp | ||||
| } | ||||
|  | ||||
| // book satisfies the fmt.Stringer | ||||
| func (b *book) String() string { | ||||
| 	p := format(b.published) | ||||
|  | ||||
| 	// product.String() has a pointer receiver. | ||||
| 	// That's why you need to manually take the product's address here. | ||||
| 	// | ||||
| 	// If you pass: "b.product", Go would pass it as a copy to Sprintf. | ||||
| 	// In that case, Go can't deference b.product automatically. | ||||
| 	// It's because: b.product would be different value—a copy. | ||||
| 	return fmt.Sprintf("%s - (%v)", &b.product, p) | ||||
| } | ||||
|  | ||||
| func format(v interface{}) string { | ||||
| 	var t int | ||||
|  | ||||
| 	switch v := v.(type) { | ||||
| 	case int: | ||||
| 		t = v | ||||
| 	case string: | ||||
| 		t, _ = strconv.Atoi(v) | ||||
| 	default: | ||||
| 		return "unknown" | ||||
| 	} | ||||
|  | ||||
| 	// Mon Jan 2 15:04:05 -0700 MST 2006 | ||||
| 	const layout = "2006/01" | ||||
|  | ||||
| 	u := time.Unix(int64(t), 0) | ||||
| 	return u.Format(layout) | ||||
| 	return fmt.Sprintf("%s - (%s)", &b.product, b.published) | ||||
| } | ||||
|   | ||||
| @@ -11,9 +11,9 @@ import "fmt" | ||||
|  | ||||
| func main() { | ||||
| 	store := list{ | ||||
| 		&book{product{"moby dick", 10}, 118281600}, | ||||
| 		&book{product{"odyssey", 15}, "733622400"}, | ||||
| 		&book{product{"hobbit", 25}, nil}, | ||||
| 		&book{product{"moby dick", 10}, toTimestamp(118281600)}, | ||||
| 		&book{product{"odyssey", 15}, toTimestamp("733622400")}, | ||||
| 		&book{product{"hobbit", 25}, unknown}, | ||||
| 		&puzzle{product{"rubik's cube", 5}}, | ||||
| 		&game{product{"minecraft", 20}}, | ||||
| 		&game{product{"tetris", 5}}, | ||||
| @@ -26,4 +26,8 @@ func main() { | ||||
| 	// but the Print function can print it. | ||||
| 	// it's because, the list satisfies the stringer. | ||||
| 	fmt.Print(store) | ||||
|  | ||||
| 	// timestamp is useful even if it's zero. | ||||
| 	var ts timestamp | ||||
| 	fmt.Println(ts) | ||||
| } | ||||
|   | ||||
							
								
								
									
										51
									
								
								interfaces/09-stringer/timestamp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								interfaces/09-stringer/timestamp.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // 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 ( | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Mon Jan 2 15:04:05 -0700 MST 2006 | ||||
| const layout = "2006/01" | ||||
|  | ||||
| // unknown is the zero value of a timestamp. | ||||
| var unknown = timestamp(time.Time{}) | ||||
|  | ||||
| // Timestamp prints timestamps, it's a stringer. | ||||
| // Timestamp is useful even if it's zero. | ||||
| type timestamp time.Time | ||||
|  | ||||
| // String makes the timestamp a stringer. | ||||
| func (ts timestamp) String() string { | ||||
| 	t := time.Time(ts) | ||||
|  | ||||
| 	if t.IsZero() { | ||||
| 		return "unknown" | ||||
| 	} | ||||
|  | ||||
| 	return t.Format(layout) | ||||
| } | ||||
|  | ||||
| // toTimestamp was "book.format" before. | ||||
| // Now it returns a timestamp value depending on the type of `v`. | ||||
| func toTimestamp(v interface{}) timestamp { | ||||
| 	var t int | ||||
|  | ||||
| 	switch v := v.(type) { | ||||
| 	case int: | ||||
| 		t = v | ||||
| 	case string: | ||||
| 		t, _ = strconv.Atoi(v) | ||||
| 	default: | ||||
| 		return unknown | ||||
| 	} | ||||
|  | ||||
| 	return timestamp(time.Unix(int64(t), 0)) | ||||
| } | ||||
| @@ -8,57 +8,14 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type book struct { | ||||
| 	product | ||||
| 	Published interface{} | ||||
| 	Published timestamp | ||||
| } | ||||
|  | ||||
| func (b book) String() string { | ||||
| 	p := format(b.Published) | ||||
| 	return fmt.Sprintf("%s - (%v)", &b.product, p) | ||||
| } | ||||
|  | ||||
| // MarshalJSON is an implementation of the json.Marshaler interface. | ||||
| // json.Marshal and Decode call this method. | ||||
| func (b *book) MarshalJSON() ([]byte, error) { | ||||
| 	// Calling Marshal creates an infinite loop because Marshal calls | ||||
| 	// MarshalJSON again and again. | ||||
| 	// | ||||
| 	// Declaring a clone type without MarshalJSON fixes the problem. | ||||
| 	type jbook book | ||||
|  | ||||
| 	// book is convertable to jbook | ||||
| 	// jbook's underlying type is book. | ||||
| 	jb := (*jbook)(b) | ||||
|  | ||||
| 	// Customize the formatting of the published field. | ||||
| 	// This will result in the published field of the resulting json. | ||||
| 	jb.Published = format(b.Published) | ||||
|  | ||||
| 	return json.Marshal(jb) | ||||
| } | ||||
|  | ||||
| func format(v interface{}) string { | ||||
| 	var t int | ||||
|  | ||||
| 	switch v := v.(type) { | ||||
| 	case int: | ||||
| 		t = v | ||||
| 	case string: | ||||
| 		t, _ = strconv.Atoi(v) | ||||
| 	default: | ||||
| 		return "unknown" | ||||
| 	} | ||||
|  | ||||
| 	// Mon Jan 2 15:04:05 -0700 MST 2006 | ||||
| 	const layout = "2006/01" | ||||
|  | ||||
| 	u := time.Unix(int64(t), 0) | ||||
| 	return u.Format(layout) | ||||
| 	return fmt.Sprintf("%s - (%s)", &b.product, b.Published) | ||||
| } | ||||
|   | ||||
| @@ -14,22 +14,85 @@ import ( | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	store := list{ | ||||
| 		&book{product{"moby dick", 10}, 118281600}, | ||||
| 		&book{product{"odyssey", 15}, "733622400"}, | ||||
| 		&book{product{"hobbit", 25}, nil}, | ||||
| 		&puzzle{product{"rubik's cube", 5}}, | ||||
| 		&game{product{"minecraft", 20}}, | ||||
| 		&game{product{"tetris", 5}}, | ||||
| 		&toy{product{"yoda", 150}}, | ||||
| 	} | ||||
| 	// store := list{ | ||||
| 	// 	&book{product{"moby dick", 10}, 118281600}, | ||||
| 	// 	&book{product{"odyssey", 15}, "733622400"}, | ||||
| 	// 	&book{product{"hobbit", 25}, nil}, | ||||
| 	// 	&puzzle{product{"rubik's cube", 5}}, | ||||
| 	// 	&game{product{"minecraft", 20}}, | ||||
| 	// 	&game{product{"tetris", 5}}, | ||||
| 	// 	&toy{product{"yoda", 150}}, | ||||
| 	// } | ||||
|  | ||||
| 	out, err := json.MarshalIndent(store, "", "\t") | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
| 	fmt.Println(string(out)) | ||||
| 	// out, err := json.MarshalIndent(store, "", "\t") | ||||
| 	// if err != nil { | ||||
| 	// 	log.Fatalln(err) | ||||
| 	// } | ||||
| 	// fmt.Println(string(out)) | ||||
|  | ||||
| 	// store.discount(.5) | ||||
| 	// fmt.Print(store) | ||||
|  | ||||
| 	encode() | ||||
| } | ||||
|  | ||||
| func encode() { | ||||
|  | ||||
| 	books := []*book{ | ||||
| 		{product{"moby dick", 10}, toTime(118281600)}, | ||||
| 		{product{"odyssey", 15}, toTime("733622400")}, | ||||
| 		{product{"hobbit", 25}, zeroTimestamp}, | ||||
| 	} | ||||
|  | ||||
| 	for _, b := range books { | ||||
| 		fmt.Println(b) | ||||
| 	} | ||||
|  | ||||
| 	out, err := json.MarshalIndent(books, "", "\t") | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(string(out)) | ||||
| } | ||||
|  | ||||
| func decode() { | ||||
| 	// books = nil | ||||
| 	out := []byte(`[ | ||||
| 	{ | ||||
| 		"Title": "moby dick", | ||||
| 		"Price": 10, | ||||
| 		"Published": "118281600" | ||||
| 	}, | ||||
| 	{ | ||||
| 		"Title": "odyssey", | ||||
| 		"Price": 15, | ||||
| 		"Published": 733622400 | ||||
| 	}, | ||||
| 	{ | ||||
| 		"Title": "hobbit", | ||||
| 		"Price": 25, | ||||
| 		"Published": -62135596800 | ||||
| 	}, | ||||
| 	{ | ||||
| 		"Title": "poka", | ||||
| 		"Price": 25, | ||||
| 		"Published": "1983/03" | ||||
| 	}, | ||||
| 	{ | ||||
| 		"Title": "fuka", | ||||
| 		"Price": 25 | ||||
| 	}	 | ||||
| ]`) | ||||
|  | ||||
| 	var books []*book | ||||
|  | ||||
| 	err := json.Unmarshal(out, &books) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|  | ||||
| 	for _, b := range books { | ||||
| 		fmt.Println(b) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user