encoding/json.Decoder.More în Go

Spune dacă mai urmează un element în lista sau obiectul citit; cu Token permite citirea element cu element a unei liste mari.

Sintaxă
func (dec *Decoder) More() bool
func (dec *Decoder) Token() (Token, error)

Ce face encoding/json.Decoder.More

dec.More() returnează true dacă în lista (sau obiectul) care se citește acum mai există un element. Împreună cu dec.Token(), care citește un singur simbol ([, ], {, o cheie…), permite parcurgerea unei liste JSON uriașe element cu element: citești [ cu Token, apoi for dec.More() { dec.Decode(&element) }, apoi ].

Așa nu ții toată lista în memorie: un fișier de 2 GB cu milioane de comenzi se procesează cu memorie constantă. La nivelul de sus (în afara unei liste), More spune dacă mai urmează date în flux, util ca să verifici că un corp nu are nimic după obiectul așteptat.

Ce returnează

More: bool. Token: simbolul citit (json.Delim, string, float64, bool, nil) și o eroare.

Exemple

Exemplul 1: O listă mare citită element cu element

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

type Comanda struct {
	ID    int     `json:"id"`
	Total float64 `json:"total"`
}

func main() {
	date := `[
		{"id": 1, "total": 120.5},
		{"id": 2, "total": 89},
		{"id": 3, "total": 310.25}
	]`
	dec := json.NewDecoder(strings.NewReader(date))

	inceput, err := dec.Token() // [
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Început:", inceput)

	suma := 0.0
	for dec.More() {
		var c Comanda
		if err := dec.Decode(&c); err != nil {
			fmt.Println(err)
			return
		}
		fmt.Printf("comanda %d: %.2f lei\n", c.ID, c.Total)
		suma += c.Total
	}
	sfarsit, _ := dec.Token() // ]
	fmt.Println("Sfârșit:", sfarsit)
	fmt.Printf("Total: %.2f lei\n", suma)
}

Rezultat

Început: [
comanda 1: 120.50 lei
comanda 2: 89.00 lei
comanda 3: 310.25 lei
Sfârșit: ]
Total: 519.75 lei

Exemplul 2: Date în plus după obiect

După Decode, More() spune dacă în corp a mai rămas ceva.

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

func unSingurObiect(text string) error {
	dec := json.NewDecoder(strings.NewReader(text))
	var v map[string]any
	if err := dec.Decode(&v); err != nil {
		return err
	}
	if dec.More() {
		return fmt.Errorf("date în plus după obiectul JSON")
	}
	return nil
}

func main() {
	fmt.Println(unSingurObiect(`{"a": 1}`))
	fmt.Println(unSingurObiect(`{"a": 1}   `))
	fmt.Println(unSingurObiect(`{"a": 1} {"b": 2}`))
}

Rezultat

<nil>
<nil>
date în plus după obiectul JSON

Greșeli frecvente

  • Faci for dec.More() pe o listă fără să citești întâi [ cu Token(): Decode încearcă să citească toată lista într-un singur element și dă eroare de tip.

Comenzi înrudite