Go言語でjsonを使う時に気をつけておきたい4つのこと

19/02/17 17:18:16     19/04/08 11:30:41

Go言語でjson

JSONとはJavaScript Object Notation の略で、JavaScriptのなかでオブジェクトを記述する書式のことです。

このページでは、のJSONの詳細や、それをGo言語で使用する際の注意点について解説します。

JSONとは

JSONの定義は上記の通りですが、これだけだといまいち内容がわからないかもしれません。人間がデータを見る際はデータベースのように表形式のようになっているとわかりやすいですが、コンピューターはそのままだと認識できません。

そこでJSONでは人間にとっての可読性も残しつつ、コンピューターが二進数に変換しやすいような形で表記したものです。

構造体とは

JSONを扱ううえで重要になるのが構造体の概念です。なぜなら、JSONの役割は文字列を構造体に変換したり、逆に構造体を文字列に変換することが主な役割だからです。この構造体が何かということですが、これは変数の型の一種です。

たとえば変数や配列の宣言を行う際に型を決めるのですが、基本的にはそこで決めた型の値しか格納することができません。配列の場合同じ型の要素を格納することになるのですが、構造体の場合要素ごとの型をばらばらにすることができます。

GoでJSONを使う時の注意点

GoにはJSONを扱うためのパッケージであるencoding/jsonが標準搭載されています。これにより、エンコード(構造体から文字列)とデコード(文字列から構造体)の両方をサポートしています。

Go言語でjsonを使う時に気をつけておきたいこと1.構造体とJSONの構造をそろえて定義する

デコード結果を受け取るには構造体とJSONの構造が同じである必要があります。以下のサンプルコードで確認してみましょう。

package main

import (
    "encoding/json"
)

type Message struct {
    Name string
    Body string
    Time int64
}

func main() {
    b := []byte(`{"Name":"name","Body":"Hello","Time":1294706395881547000}`)
    var m Message
    json.Unmarshal(b, &m)
    println(m.Name)
}

上記のコードを実行するとnameと出力されます。

Go言語でjsonを使う時に気をつけておきたいこと2.ネストすると読みにくい

プログラミングしていて入れ子が深くなってしまうことがありますが、JSONを扱う場合ネスト回数が多いと可読性が著しく下がります。なぜなら、結果を受け取る構造体もネストで定義する必要があるからです。サンプルコードで確認しましょう。

{
    "took": 1,
    "timed_out": false,
    "_shards":{
        "total" : 1,
        "successful" : 1,
        "failed" : 0
    },
    "hits":{
        "total" : 1,
        "max_score": 1.3862944,
        "hits" : [
            {
                "_index" : "twitter",
                "_type" : "tweet",
                "_id" : "0",
                "_score": 1.3862944,
                "_source" : {
                    "user" : "kimchy",
                    "message": "trying out Elasticsearch",
                    "date" : "2019-02-16T14:12:12",
                    "likes" : 0
                }
            }
        ]
    }
}

このネスト回数の多いAPIに対応するJSONコードは以下のようになります。

package main

import (
    "encoding/json"
    "net/http"
)

type ResultShards struct {
    Total int `json:"total"`
    Successful int `json:"successful"`
    Failed int `json:"failed"`
}

type ResultHitSource struct {
    User string `json:"user"`
    Message string `json:"message"`
    Date string `json:"date"`
    Likes int `json:"likes"`
}

type ResultHit struct {
    Index string `json:"_index"`
    Type string `json:"_type"`
    Id string `json:"_id"`
    Score float32 `json:"_score"`
    Source ResultHitSource `json:"_source"`
}

type ResultHits struct {
    Total int `json:"total"`
    MaxScore float32 `json:"max_score"`
    Hits []ResultHit `json:"hits"`
}

type Result struct {
    Took int `json:"took"`
    TimedOut bool `json:"timed_out"`
    Shards ResultShards `json:"_shards"`
    Hits ResultHits `json:"hits"`
}

func main() {
    resp, err := http.Get("http://127.0.0.1:9200/_search")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    var result Result
    if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
        panic(err)
    }
    println(result.Hits.Total)
}

API実装のたびにこのようなJSONが必要になるので、コードの可読性が低くなおかつメモリの無駄遣いです。処理が速く軽量なGo言語の魅力を失うことになるので、改良の余地があります。

Go言語でjsonを使う時に気をつけておきたいこと3.コードの可読性を上げる

上の話とつながっていますが、JSONコードの冗長さをなくすためにリファクタリングを行い、可読性を高めます。リファクタリングとは、処理結果は同じままで、内部処理のみの効率性を高めることです。処理結果が同じなら、内部ロジックはなるべくシンプルな方が良いからです。

Go言語でjsonを使う時に気をつけておきたいこと4.必要なオブジェクトのみを取り出す

すべてのオブジェクトを取り出すと無駄な処理が増えるため、必要なオブジェクトのみを抽出します。方法としては構造体の代わりにinterface型として結果の格納先を定義することで、構造体定義を省略できます。

package main

import (
    "encoding/json"
    "net/http"
)

func main() {
    resp, err := http.Get("http://127.0.0.1:9200/_search")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    var result interface{}
    decoder := json.NewDecoder(resp.Body)
    if err := decoder.Decode(&result); err != nil {
        panic(err)
    }
    n, _ := result.(map[string]interface{})["hits"].(map[string]interface{})["total"].(float64)
    println(int(n))
}

数値型がすべてfloat型で取得されるため、int型で出力したい場合は変換する手間が生じます。それでもすべてのオブジェクトを取得するよりはコードが短くなって処理が軽くなる場合がほとんどなので、数値型を変換する手間くらいは問題ではないかと思います。

他にもJSONには使い方やメソッドがありますが、JSONの概念自体ややこしいので一度にすべて把握する必要はないでしょう。あとは複雑な処理をする際はライブラリも配布されているので、実装する前にライブラリを探してみることをおすすめします。

案件量が豊富なアルマサーチ

アルマサーチ

最後に、アルマサーチのご紹介!

アルマサーチはフリーランス向けに案件をご紹介することに特化したエージェントサービスです。豊富な案件量から、安定して継続的な案件のご紹介を実現しており、口コミから登録エンジニアが急増中です。

アルマサーチが選ばれる理由

  1. 豊富な案件量。週3〜4日の案件や在宅リモート案件も。
  2. 優秀なコンサルタント陣。
  3. 案件に参画後もしっかりサポート。

豊富な案件量

フリーランス向けに特化し、業界屈指の案件量を誇ります!週3〜4日の案件や、在宅リモート案件もありますし、その他あらゆる希望をしっかりお伝えください。最適な案件のご紹介をさせていただきます。

優秀なコンサルタント陣

技術に疎く、開発の希望を伝えても響かないエージェント・・・嫌ですよね。アルマサーチにはそのような者は一切おりません!さらに独立にまつわる税金や保険関係に詳しいスタッフが徹底的にサポートさせていただきます。

案件に参画後もしっかりサポート

常駐先が決まった瞬間に、一度も連絡が取れなくなるエージェント・・・いますよね?アルマサーチでは、そのようなことは一切ありません!常に電話やメールは即対応しますし、月に1度のランチミーティングなどから現場の状況を細かくヒアリングし、就業環境改善に尽力いたします。

相談する

▼Go言語関連の記事 
1, 【Go言語の求人・案件情報】特徴やメリット、採用している会社やエンジニア開発単価まで
2, 【Go言語入門】Go言語を初めて学ぶ人がチェックしたい学習サイト5選
3, Go言語の特徴とできることを、現役プログラマに聞いてみた
4, Go言語のフレームワークをそれぞれ比較してみました
5, 未経験者におすすめのGo言語の書籍5選
6, (この記事)Go言語でjsonを使う時に気をつけておきたい4つのこと
7, Go言語の開発環境をWindowsで構築する方法まとめ
8, なぜPythonからGo言語にスキルチェンジする人が多いのか?
9, Go言語の実行速度は速いのか?他の言語と比べてみました
10, Go言語は難しい?スキルチェンジしたエンジニアに聞いてみた

人気記事

編集部おすすめ記事

この記事を読んだ人はこんな記事を読んでいます

案件探しやフリーランスになるための相談する