Go Cookbook
上QQ阅读APP看书,第一时间看更新

How to do it...

These steps cover writing and running your application:

  1. From your terminal/console application, create and navigate to the chapter3/nulls directory.
  2. Copy tests from https://github.com/agtorre/go-cookbook/tree/master/chapter3/nulls or use this as an exercise to write some of your own code.
  3. Create a file called base.go with the following contents:
        package nulls

import (
"encoding/json"
"fmt"
)

// json that has name but not age
const (
jsonBlob = `{"name": "Aaron"}`
fulljsonBlob = `{"name":"Aaron", "age":0}`
)

// Example is a basic struct with age
// and name fields
type Example struct {
Age int `json:"age,omitempty"`
Name string `json:"name"`
}

// BaseEncoding shows encoding and
// decoding with normal types
func BaseEncoding() error {
e := Example{}

// note that no age = 0 age
if err := json.Unmarshal([]byte(jsonBlob), &e); err != nil
{
return err
}
fmt.Printf("Regular Unmarshal, no age: %+v\n", e)

value, err := json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("Regular Marshal, with no age:", string(value))

if err := json.Unmarshal([]byte(fulljsonBlob), &e);
err != nil {
return err
}
fmt.Printf("Regular Unmarshal, with age = 0: %+v\n", e)

value, err = json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("Regular Marshal, with age = 0:",
string(value))

return nil
}
  1. Create a file called pointer.go with the following contents:
        package nulls

import (
"encoding/json"
"fmt"
)

// ExamplePointer is the same, but
// uses a *Int
type ExamplePointer struct {
Age *int `json:"age,omitempty"`
Name string `json:"name"`
}

// PointerEncoding shows methods for
// dealing with nil/omitted values
func PointerEncoding() error {

// note that no age = nil age
e := ExamplePointer{}
if err := json.Unmarshal([]byte(jsonBlob), &e); err != nil
{
return err
}
fmt.Printf("Pointer Unmarshal, no age: %+v\n", e)

value, err := json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("Pointer Marshal, with no age:", string(value))

if err := json.Unmarshal([]byte(fulljsonBlob), &e);
err != nil {
return err
}
fmt.Printf("Pointer Unmarshal, with age = 0: %+v\n", e)

value, err = json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("Pointer Marshal, with age = 0:",
string(value))

return nil
}
  1. Create a file called nullencoding.go with the following contents:
        package nulls

import (
"database/sql"
"encoding/json"
"fmt"
)

type nullInt64 sql.NullInt64

// ExampleNullInt is the same, but
// uses a sql.NullInt64
type ExampleNullInt struct {
Age *nullInt64 `json:"age,omitempty"`
Name string `json:"name"`
}

func (v *nullInt64) MarshalJSON() ([]byte, error) {
if v.Valid {
return json.Marshal(v.Int64)
}
return json.Marshal(nil)
}

func (v *nullInt64) UnmarshalJSON(b []byte) error {
v.Valid = false
if b != nil {
v.Valid = true
return json.Unmarshal(b, &v.Int64)
}
return nil
}

// NullEncoding shows an alternative method
// for dealing with nil/omitted values
func NullEncoding() error {
e := ExampleNullInt{}

// note that no means an invalid value
if err := json.Unmarshal([]byte(jsonBlob), &e); err != nil
{
return err
}
fmt.Printf("nullInt64 Unmarshal, no age: %+v\n", e)

value, err := json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("nullInt64 Marshal, with no age:",
string(value))

if err := json.Unmarshal([]byte(fulljsonBlob), &e);
err != nil {
return err
}
fmt.Printf("nullInt64 Unmarshal, with age = 0: %+v\n", e)

value, err = json.Marshal(&e)
if err != nil {
return err
}
fmt.Println("nullInt64 Marshal, with age = 0:",
string(value))

return nil
}
  1. Create a new directory named example.
  2. Navigate to example.
  3. Create a file called main.go with the following contents; be sure to modify the nulls import to use the path you set up in step 2:
        package main

import (
"fmt"

"github.com/agtorre/go-cookbook/chapter3/nulls"
)

func main() {
if err := nulls.BaseEncoding(); err != nil {
panic(err)
}
fmt.Println()

if err := nulls.PointerEncoding(); err != nil {
panic(err)
}
fmt.Println()

if err := nulls.NullEncoding(); err != nil {
panic(err)
}
}
  1. Run go run main.go.
  2. You could also run this:
      go build
./example

You should see the following output:

      $ go run main.go
Regular Unmarshal, no age: {Age:0 Name:Aaron}
Regular Marshal, with no age: {"name":"Aaron"}
Regular Unmarshal, with age = 0: {Age:0 Name:Aaron}
Regular Marshal, with age = 0: {"name":"Aaron"}

Pointer Unmarshal, no age: {Age:<nil> Name:Aaron}
Pointer Marshal, with no age: {"name":"Aaron"}
Pointer Unmarshal, with age = 0: {Age:0xc42000a610 Name:Aaron}
Pointer Marshal, with age = 0: {"age":0,"name":"Aaron"}

nullInt64 Unmarshal, no age: {Age:<nil> Name:Aaron}
nullInt64 Marshal, with no age: {"name":"Aaron"}
nullInt64 Unmarshal, with age = 0: {Age:0xc42000a750
Name:Aaron}

nullInt64 Marshal, with age = 0: {"age":0,"name":"Aaron"}
  1. If you copied or wrote your own tests, go up one directory and run go test. Ensure that all tests pass.