refactor: marshaler unmarshaler iface

This commit is contained in:
Inanc Gumus
2019-10-21 15:21:34 +03:00
parent 59865eac28
commit 3ac59459fd
13 changed files with 83 additions and 38 deletions

View File

@ -7,9 +7,7 @@
package main
import (
"encoding/json"
)
import "encoding/json"
func encode() ([]byte, error) {
l := list{
@ -17,13 +15,12 @@ func encode() ([]byte, error) {
{Title: "odyssey", Price: 15, Released: toTimestamp("733622400")},
{Title: "hobbit", Price: 25},
}
return json.MarshalIndent(l, "", "\t")
}
func decode(data []byte) (l list, err error) {
func decode(data []byte) (l list, _ error) {
if err := json.Unmarshal(data, &l); err != nil {
return nil, err
}
return l, nil
return
}

View File

@ -8,6 +8,7 @@
package main
import (
"sort"
"strings"
)
@ -34,16 +35,20 @@ func (l list) discount(ratio float64) {
}
}
// implementation of the sort.Interface:
// by default `list` sorts by `Title`.
func (l list) Len() int { return len(l) }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l list) Less(i, j int) bool { return l[i].Title < l[j].Title }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
// byRelease sorts by product release dates.
type byRelease struct {
list
}
type byRelease struct{ list }
func (bp byRelease) Less(i, j int) bool {
return bp.list[i].Released.Before(bp.list[j].Released.Time)
}
func byReleaseDate(l list) sort.Interface {
return &byRelease{l}
}

View File

@ -9,13 +9,45 @@ package main
import (
"fmt"
"log"
)
func main() {
// removed error handling for brevity (normally you shouldn't do this).
out, _ := encode()
fmt.Println(string(out))
// First encode products as JSON:
data, err := encode()
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(data))
l, _ := decode(out)
// Then decode them back from JSON:
l, err := decode(data)
if err != nil {
log.Fatalln(err)
}
// Let the list value print itself:
fmt.Print(l)
}
/*
Summary:
- json.Marshal() and json.MarshalIndent() can only encode primitive types.
- It cannot encode custom types.
- Implement the json.Marshaler interface and teach it how to encode your custom types.
- See time.Time code: It satisfies the json.Marshaler interface.
- json.Unmarshal() can only decode primitive types.
- It cannot decode custom types.
- Implement the json.Unmarshaler interface and teach it how to decode your custom types.
- See time.Time code: It satisfies the json.Unmarshaler interface as well.
- strconv.AppendInt() can append an int value to a []byte.
- There are several other functions in the strconv package for other primitive types as well.
- Do not make unnecessary string <-> []byte conversions.
- log.Fatalln() can print the given error message and terminate the program.
- Use it only from the main(). Do not use it in other functions.
- main() is should be the main driver of a program.
*/

View File

@ -14,7 +14,7 @@ import (
type product struct {
Title string `json:"title"`
Price money `json:"price"`
Released timestamp `json:"released,omitempty"`
Released timestamp `json:"released"`
}
func (p *product) String() string {

View File

@ -16,6 +16,8 @@ type timestamp struct {
time.Time
}
// implementation of the fmt.Stringer interface:
func (ts timestamp) String() string {
if ts.IsZero() {
return "unknown"
@ -26,8 +28,9 @@ func (ts timestamp) String() string {
return ts.Format(layout)
}
// implementation of the json.Marshaler and json.Unmarshaler interfaces:
// timestamp knows how to decode itself from json.
// UnmarshalJSON is an implementation of the json.Unmarshaler interface.
// json.Unmarshal and json.Decode call this method.
func (ts *timestamp) UnmarshalJSON(data []byte) error {
*ts = toTimestamp(string(data))
@ -35,11 +38,9 @@ func (ts *timestamp) UnmarshalJSON(data []byte) error {
}
// timestamp knows how to encode itself to json.
// MarshalJSON is an implementation of the json.Marshaler interface.
// json.Marshal and json.Encode call this method.
func (ts timestamp) MarshalJSON() (out []byte, err error) {
// return ts.Time.MarshalJSON()
return strconv.AppendInt(out, ts.Unix(), 10), nil
func (ts timestamp) MarshalJSON() (data []byte, _ error) {
return strconv.AppendInt(data, ts.Unix(), 10), nil
}
func toTimestamp(v interface{}) (ts timestamp) {

View File

@ -24,11 +24,11 @@ func encode() ([]byte, error) {
return json.MarshalIndent(l, "", "\t")
}
func decode(data []byte) (l list, err error) {
func decode(data []byte) (l list, _ error) {
if err := json.Unmarshal(data, &l); err != nil {
return nil, err
}
return l, nil
return
}
func decodeFile(path string) (list, error) {

View File

@ -8,6 +8,7 @@
package main
import (
"sort"
"strings"
)
@ -34,16 +35,20 @@ func (l list) discount(ratio float64) {
}
}
// by default `list` sorts by `Title`.
// implementation of the sort.Interface:
// by default `list` sorts by `title`.
func (l list) Len() int { return len(l) }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l list) Less(i, j int) bool { return l[i].Title < l[j].Title }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
// byRelease sorts by product release dates.
type byRelease struct {
list
}
type byRelease struct{ list }
func (bp byRelease) Less(i, j int) bool {
return bp.list[i].Released.Before(bp.list[j].Released.Time)
}
func byReleaseDate(l list) sort.Interface {
return &byRelease{l}
}

View File

@ -14,7 +14,7 @@ import (
type product struct {
Title string `json:"title"`
Price money `json:"price"`
Released timestamp `json:"released,omitempty"`
Released timestamp `json:"released"`
}
func (p *product) String() string {

View File

@ -31,7 +31,7 @@ func (ts *timestamp) UnmarshalJSON(data []byte) error {
return nil
}
func (ts timestamp) MarshalJSON() (out []byte, err error) {
func (ts timestamp) MarshalJSON() (out []byte, _ error) {
return strconv.AppendInt(out, ts.Unix(), 10), nil
}

View File

@ -24,11 +24,11 @@ func encode() ([]byte, error) {
return json.MarshalIndent(l, "", "\t")
}
func decode(data []byte) (l list, err error) {
func decode(data []byte) (l list, _ error) {
if err := json.Unmarshal(data, &l); err != nil {
return nil, err
}
return l, nil
return
}
func decodeFile(path string) (list, error) {

View File

@ -8,6 +8,7 @@
package main
import (
"sort"
"strings"
)
@ -34,16 +35,20 @@ func (l list) discount(ratio float64) {
}
}
// by default `list` sorts by `Title`.
// implementation of the sort.Interface:
// by default `list` sorts by `title`.
func (l list) Len() int { return len(l) }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l list) Less(i, j int) bool { return l[i].Title < l[j].Title }
func (l list) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
// byRelease sorts by product release dates.
type byRelease struct {
list
}
type byRelease struct{ list }
func (bp byRelease) Less(i, j int) bool {
return bp.list[i].Released.Before(bp.list[j].Released.Time)
}
func byReleaseDate(l list) sort.Interface {
return &byRelease{l}
}

View File

@ -14,7 +14,7 @@ import (
type product struct {
Title string `json:"title"`
Price money `json:"price"`
Released timestamp `json:"released,omitempty"`
Released timestamp `json:"released"`
}
func (p *product) String() string {

View File

@ -31,7 +31,7 @@ func (ts *timestamp) UnmarshalJSON(data []byte) error {
return nil
}
func (ts timestamp) MarshalJSON() (out []byte, err error) {
func (ts timestamp) MarshalJSON() (out []byte, _ error) {
return strconv.AppendInt(out, ts.Unix(), 10), nil
}