Golang基礎学習:StructとJson

55477 ワード

前言
構造体は、複数の任意のタイプの命名変数を組み合わせた集約データ型であり、構造体によって多次元/態様の集約論理データを形成し、全体を形成することができ、これらの命名変数を構造体のメンバーと呼ぶ.
Struct
宣言:
//          
type Employee struct {
     
	ID        int
	Name      string
	Address   string
	DoB       string
	Position  string
	Salary    int
	ManagerID int
}

構造体メンバー(変数名)は、jsonとの変換を容易にするために大文字で始まることをお勧めします.具体的には、後述の部分を見ることができます.
単純な使用
	//           ,    ,          ,             ,         :
	var bob *Employee = new(Employee)  // &{0     0 0}
	var claier *Employee = &Employee{
     } // &{0     0 0}
	var alice Employee                 // {0     0 0}
	fmt.Println(bob, claier, alice)

	//      
	alice.Salary = 3000
	fmt.Println(alice, alice.Salary) // {0     3000 0} 3000

	//          
	position := &bob.Position
	*position = "Senior"
	fmt.Println(bob) // &{0    Senior 0 0}

	c := &claier
	(*c).Name = "claier"
	fmt.Println(*c) // &{0 alice   Senior 3000 0}

構造と比較
	/*
		    :
			struct           ,       
	*/
	
    func NewEmployee(id int, name string) *Employee {
     
    	return &Employee{
     ID: id, Name: name}
    }

	david := NewEmployee(4, "david")
	fmt.Println(*david) // {4 david    0 0}

	/*
		struct     
	*/
	// struct          ,      。     ,map key            ,  struct    map key
	fmt.Println(alice == *bob) // false

	type url struct {
     
		host string
		port int
	}
	pageViews := make(map[url]int)
	pageViews[url{
     "www.baidu.com", 443}]++

構造体ネスト
	/*
										struct  
		struct      ,                          ,       :
		     :    ->    ->    ->   
	*/
	//     

	type School struct {
     
		name string
	}

	type Grade struct {
     
		level  int
		school School
	}

	type Classes struct {
     
		grade Grade
		id    int
	}
	type Student struct {
     
		name    string
		age     int
		classes Classes
	}

	var xiaoming Student
	xiaoming.name = "xiaoming"
	xiaoming.classes.grade.school.name = "NO.1 School"
	xiaoming.classes.grade.level = 3
	xiaoming.classes.id = 2
	xiaoming.age = 8
	fmt.Println(xiaoming) // {xiaoming 8 {
     {3 {NO.1 School}} 2}}

匿名構造体ネスト
	/*
	       :
		    ,               ,                。       ,             ,           
, , ( )。 ,xiaoli.name Student2.name,
xiaoli.classes.grade.school.name, xiaoli.School.name 。 , , 。 */
type Grade2 struct { level int School } type Classes2 struct { Grade2 id int } type Student2 struct { name string age int Classes2 } var xiaoli Student2 xiaoli.name = "xiaoli" xiaoli.School.name = "NO.2 School" // xiaoli.classes.grade.school.name xiaoli.level = 4 // xiaoli.classes.grade.level xiaoli.id = 3 // xiaoli.classes.id xiaoli.age = 9 fmt.Println(xiaoli) // {xiaoli 9 { {4 {NO.2 School}} 3}} // xiaohong := Student2{ "xiaohong", 11, Classes2{ Grade2{ 5, School{ "NO.2 School"}}, 4}} // xiaotian := Student2{ "xiaotian", 12, Classes2{ Grade2{ 6, School{ "NO.2 School", }, }, 5, }, } fmt.Println(xiaohong) // {xiaohong 11 { {5 {NO.2 School}} 4}} fmt.Println(xiaotian) // {xiaotian 12 { {6 {NO.2 School}} 5}}

JSON
Jsonは非常に一般的なデータ受信と送信のフォーマット基準であり、その論理構造はstructと非常に似ており、goはjsonデータの処理と変換操作をサポートするために標準ライブラリencoding/jsonを提供している.次にstructとjsonの間の変換を例に挙げます.
struct=>jsonシーケンス化
	type Movie struct {
     
		Name  string
		Year  int
		actor []string
	}

	var movies = []Movie{
     
		{
     Name: "movie1", Year: 1999, actor: []string{
     "zhangsan", "lisi"}},
		{
     Name: "movie2", Year: 2000, actor: []string{
     "wangwu", "zhaoliu"}},
	}

	data, err := json.Marshal(movies)
	if err != nil {
     
		fmt.Println("Json parse error")
		return
	}
	fmt.Println(movies)      // [{movie1 1999 [zhangsan lisi]} {movie2 2000 [wangwu zhaoliu]}]
	fmt.Printf("%s
"
, data) // [{"Name":"movie1","Year":1999},{"Name":"movie2","Year":2000}] // : actor , JSON struct , , 。

上記の例では、jsonシーケンス化時に小文字の先頭の構造体メンバーは無視されます.json処理時にメンバーを小文字または別名として表示する場合は、ラベルを表示して追加できます.
	type Movie2 struct {
		Name  string
		Year  int
		Actor []string `json:"actor"`
	}
	var movies2 = []Movie2{
		{Name: "movie1", Year: 1999, Actor: []string{"zhangsan", "lisi"}},
		{Name: "movie2", Year: 2000, Actor: []string{"wangwu", "zhaoliu"}},
	}
	data2, _ := json.Marshal(movies2)
	fmt.Printf("%s
", data2) // [{"Name":"movie1","Year":1999,"actor":["zhangsan","lisi"]},{"Name":"movie2","Year":2000,"actor":["wangwu","zhaoliu"]}]

このとき出力されるメンバーactorは小文字であり,同様にラベルはここでも別名と書くことができる.注意:json:"actor"、コロンの間にスペースはありません.
json=>struct逆シーケンス化
    //              
	//var movies3 Movie2
	//         ,      .   :
	//       Movie2             data2 json       ,  :json: cannot unmarshal array into Go value of type main.Movie2
	//    :  json                ,       struct    ,  ,     movies3     []Movie2 slice  。go            ,  !
	//   ,     unmarshal    ,    json.Decoder                  json  ,        json_template.go    。

	var movies3 []Movie2
    
	err2 := json.Unmarshal(data2, &movies3)
	if err2 != nil {
		fmt.Println("Json parse error", err2)
	}
	fmt.Printf("%v
", movies3) // [{movie1 1999 [zhangsan lisi]} {movie2 2000 [wangwu zhaoliu]}] fmt.Println(movies3[0].Year) // 1999

ここではピットを踏むことに注意せず、data 2はシーケンス化前に[]Movie2のslice構造であり、Movie 2 structタイプの変数ポインタを宣言してjson逆シーケンス化のデータを受信際に異常を投げ出す、ここでも[]Movie2のsliceタイプ変数を同様に使用すべきである.
ここで用いるUnmarshalメソッドに適用するオブジェクトは、既に単一またはメモリに存在するjsonオブジェクトであり、ファイル(socket/http等)が読み取るbyteストリームjsonデータに関しては、別の逆シーケンス化方式jsonを用いることが好適である.Decoder()は、バイトストリームを一度にメモリに読み込むのではなく、これらのシーンに適用されます.
使用例
package main

/*
  Github issue api   json      go struct demo
*/

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const IssueURL = "https://api.github.com/search/issues"

type IssuesSearchResult struct {
     
	TotalCount int `json:"total_count"`
	Items      []*Issue
}

type Issue struct {
     
	Number   int
	HTMLURL  string `json:"html_url"`
	Title    string
	State    string
	User     *User
	CreateAt time.Time `json:"created_at"`
	Body     string
}

type User struct {
     
	Login   string
	HTMLURL string `json:"html_url"`
}

func SearchIssues(terms []string) (*IssuesSearchResult, error) {
     
	q := url.QueryEscape(strings.Join(terms, " ")) // slice      
	resp, err := http.Get(IssueURL + "?q=" + q)
	if err != nil {
     
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
     
		resp.Body.Close()
		return nil, err
	}
	var result IssuesSearchResult
	//   json.NewDecoder().decode()          ,     unmarshal   ,unmarshal          。
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
     
		resp.Body.Close()
		return nil, err
	}
	resp.Body.Close()
	return &result, nil
}

func main() {
     
	res, err := SearchIssues(os.Args[1:]) //      : go run ./json_template.go repo:golang/go is:open json decoder       ,     url        
	if err != nil {
     
		log.Fatal(err)
	}
	fmt.Println(res.Items[0].Title)
	fmt.Printf("%d issues: 
"
, res.TotalCount) for _, item := range res.Items { fmt.Printf( "IssueID: #%d\tTime: %s\tUser: %s\tTitle: %s
"
, item.Number, item.CreateAt, item.User.Login, item.Title) } }

実行結果:
encoding/json: second decode after error impossible
35 issues: 
IssueID: #31701 Time: 2019-04-26 20:50:17 +0000 UTC     User: lr1980    Title: encoding/json: second decode after error impossible
IssueID: #31789 Time: 2019-05-01 18:30:06 +0000 UTC     User: mgritter  Title: encoding/json: provide a way to limit recursion depth
IssueID: #29688 Time: 2019-01-11 17:07:05 +0000 UTC     User: sheerun   Title: proposal: encoding/json: add InputOffset to json decoder
IssueID: #29686 Time: 2019-01-11 16:38:04 +0000 UTC     User: sheerun   Title: json: Add InputOffset for stream byte offset access
IssueID: #28923 Time: 2018-11-22 13:50:18 +0000 UTC     User: mvdan     Title: encoding/json: speed up the decoding scanner
IssueID: #11046 Time: 2015-06-03 19:25:08 +0000 UTC     User: kurin     Title: encoding/json: Decoder internally buffers full input
IssueID: #29035 Time: 2018-11-30 11:21:31 +0000 UTC     User: jaswdr    Title: proposal: encoding/json: add error var to compare  the returned error when using json.Decoder.DisallowUnknownFields()
IssueID: #30301 Time: 2019-02-18 19:49:27 +0000 UTC     User: zelch     Title: encoding/xml: option to treat unknown fields as an error
IssueID: #30701 Time: 2019-03-09 12:16:34 +0000 UTC     User: LouAdrien Title: encoding/json: ignore tag "-" not working on embedded sub structure when decoding
IssueID: #12001 Time: 2015-08-03 19:14:17 +0000 UTC     User: lukescott Title: encoding/json: Marshaler/Unmarshaler not stream friendly
IssueID: #16212 Time: 2016-06-29 16:07:36 +0000 UTC     User: josharian Title: encoding/json: do all reflect work before decoding
IssueID: #28143 Time: 2018-10-11 07:08:25 +0000 UTC     User: Carpetsmoker      Title: proposal: encoding/json: add "readonly" tag
IssueID: #26946 Time: 2018-08-12 18:19:01 +0000 UTC     User: deuill    Title: encoding/json: clarify what happens when unmarshaling into a non-empty interface{
     }
IssueID: #5901  Time: 2013-07-17 16:39:15 +0000 UTC     User: rsc       Title: encoding/json: allow override type marshaling
IssueID: #27179 Time: 2018-08-23 18:21:32 +0000 UTC     User: lavalamp  Title: encoding/json: no way to preserve the order of map keys
IssueID: #21823 Time: 2017-09-09 21:43:31 +0000 UTC     User: 243083df  Title: encoding/xml: very low performance in xml parser
IssueID: #22752 Time: 2017-11-15 23:46:13 +0000 UTC     User: buyology  Title: proposal: encoding/json: add access to the underlying data causing UnmarshalTypeError
IssueID: #14750 Time: 2016-03-10 13:04:44 +0000 UTC     User: cyberphone        Title: encoding/json: parser ignores the case of member names
IssueID: #20754 Time: 2017-06-22 14:19:31 +0000 UTC     User: rsc       Title: encoding/xml: unmarshal only processes first XML element
IssueID: #28189 Time: 2018-10-13 16:22:53 +0000 UTC     User: adnsv     Title: encoding/json: confusing errors when unmarshaling custom types
IssueID: #7213  Time: 2014-01-27 00:23:01 +0000 UTC     User: davecheney        Title: cmd/compile: escape analysis oddity
IssueID: #7872  Time: 2014-04-26 17:47:25 +0000 UTC     User: extemporalgenome  Title: encoding/json: Encoder internally buffers full output
IssueID: #20528 Time: 2017-05-30 11:45:14 +0000 UTC     User: jvshahid  Title: net/http: connection reuse does not work happily with normal use of json package
IssueID: #17609 Time: 2016-10-26 16:07:27 +0000 UTC     User: nathanjsweet      Title: encoding/json: ambiguous fields are marshalled
IssueID: #19636 Time: 2017-03-21 12:25:10 +0000 UTC     User: josselin-c        Title: encoding/base64: decoding is slow
IssueID: #22816 Time: 2017-11-20 13:12:06 +0000 UTC     User: ganelon13 Title: encoding/json: include field name in unmarshal error messages when extracting time.Time
IssueID: #21092 Time: 2017-07-19 23:11:40 +0000 UTC     User: trotha01  Title: encoding/json: unmarshal into slice reuses element data between len and cap
IssueID: #28941 Time: 2018-11-25 14:06:38 +0000 UTC     User: mvdan     Title: cmd/compile: teach prove about slice expressions
IssueID: #15808 Time: 2016-05-24 02:13:10 +0000 UTC     User: randall77 Title: cmd/compile: loads/constants not lifted out of loop
IssueID: #28952 Time: 2018-11-26 09:59:26 +0000 UTC     User: mvdan     Title: cmd/compile: consider teaching prove about unexported integer fields


まとめ
Golang構造体には多くの特性があり,jsonと密接に結合しており,後日よく用いられ,熟練した把握が必要である.