diff --git a/interfaces/12-marshaler/json.go b/interfaces/12-marshaler/json.go index b4018db..b26a7df 100644 --- a/interfaces/12-marshaler/json.go +++ b/interfaces/12-marshaler/json.go @@ -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 } diff --git a/interfaces/12-marshaler/list.go b/interfaces/12-marshaler/list.go index b501e9f..e313b8f 100644 --- a/interfaces/12-marshaler/list.go +++ b/interfaces/12-marshaler/list.go @@ -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} +} diff --git a/interfaces/12-marshaler/main.go b/interfaces/12-marshaler/main.go index 985fc12..a238fd9 100644 --- a/interfaces/12-marshaler/main.go +++ b/interfaces/12-marshaler/main.go @@ -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. +*/ diff --git a/interfaces/12-marshaler/product.go b/interfaces/12-marshaler/product.go index 356b0d7..20d51ab 100644 --- a/interfaces/12-marshaler/product.go +++ b/interfaces/12-marshaler/product.go @@ -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 { diff --git a/interfaces/12-marshaler/timestamp.go b/interfaces/12-marshaler/timestamp.go index ebc9c0a..b23a1bd 100644 --- a/interfaces/12-marshaler/timestamp.go +++ b/interfaces/12-marshaler/timestamp.go @@ -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) { diff --git a/interfaces/13-io/json.go b/interfaces/13-io/json.go index 7507c96..deca712 100644 --- a/interfaces/13-io/json.go +++ b/interfaces/13-io/json.go @@ -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) { diff --git a/interfaces/13-io/list.go b/interfaces/13-io/list.go index b501e9f..94f5c04 100644 --- a/interfaces/13-io/list.go +++ b/interfaces/13-io/list.go @@ -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} +} diff --git a/interfaces/13-io/product.go b/interfaces/13-io/product.go index 356b0d7..20d51ab 100644 --- a/interfaces/13-io/product.go +++ b/interfaces/13-io/product.go @@ -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 { diff --git a/interfaces/13-io/timestamp.go b/interfaces/13-io/timestamp.go index 940fc11..791bbe1 100644 --- a/interfaces/13-io/timestamp.go +++ b/interfaces/13-io/timestamp.go @@ -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 } diff --git a/interfaces/14-composition/json.go b/interfaces/14-composition/json.go index 7507c96..deca712 100644 --- a/interfaces/14-composition/json.go +++ b/interfaces/14-composition/json.go @@ -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) { diff --git a/interfaces/14-composition/list.go b/interfaces/14-composition/list.go index b501e9f..94f5c04 100644 --- a/interfaces/14-composition/list.go +++ b/interfaces/14-composition/list.go @@ -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} +} diff --git a/interfaces/14-composition/product.go b/interfaces/14-composition/product.go index 356b0d7..20d51ab 100644 --- a/interfaces/14-composition/product.go +++ b/interfaces/14-composition/product.go @@ -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 { diff --git a/interfaces/14-composition/timestamp.go b/interfaces/14-composition/timestamp.go index 940fc11..791bbe1 100644 --- a/interfaces/14-composition/timestamp.go +++ b/interfaces/14-composition/timestamp.go @@ -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 }