Мэдээ

15 жилийн дараа: Go хэлний стандарт санд `encoding/json/v2` албан ёсоор тогтвортой (stable) боллоо

TOGTOKHTOGTOKH·2026 оны арван нэгдүгээр сарын 4·1 үзсэн·
15 жилийн дараа: Go хэлний стандарт санд `encoding/json/v2` албан ёсоор тогтвортой (stable) боллоо

Go хэлээр бэкенд систем, микросервис, өндөр ачаалалтай веб сервис хөгжүүлдэг хэн бүхний хамгийн түрүүнд импортолдог сан бол гарцаагүй encoding/json байдаг. Гэвч энэхүү стандарт сан нь Go 1.0 гарахаас ч өмнө буюу одоогоос 15 гаруй жилийн өмнө анх бичигдсэн бөгөөд олон жилийн турш хөгжүүлэгчдийн дунд хамгийн их шүүмжлэл, маргаан дагуулсан хэсгүүдийн нэг байв.

Go-ийн үндсэн хөгжүүлэгчдийн баг албан ёсоор "A new Go API for JSON" нийтлэлээ нийтэлж, олон нийтийн 6 жилийн тасралтгүй хөдөлмөрийн үр дүн болсон encoding/json/v2 болон encoding/json/jsontext сангуудыг Go 1.27 хувилбар дээр албан ёсоор stable болгон зарлалаа.

Энэхүү шинэчлэл нь Go-ийн түүхэнд хийгдсэн хамгийн том стандарт сангийн хувьсал бөгөөд бидний өдөр тутмын кодод хэрхэн нөлөөлөхийг хамтдаа сонирхоцгооё.


1. Хуучин v1 санд ямар 15 жилийн зовлон байсан бэ?

Go хэлний хамгийн том зарчим бол "Go 1 Compatibility Promise" буюу өмнөх хувилбарт бичигдсэн код шинэ хувилбар дээр эвдрэлгүй ажиллах баталгаа юм. Гэвч энэ дүрэм нь encoding/json-д байсан дараах суурь алдаануудыг засахад хамгийн том чөдөр болж байлаа:

  • Чимээгүй өгөгдлийн эвдрэл (Silent Data Corruption): RFC 8259 стандартын дагуу JSON нь заавал хүчинтэй UTF-8 байх ёстой. Гэтэл v1 нь буруу UTF-8 байт тааралдвал алдаа буцаахын оронд чимээгүйхэн \uFFFD (Unicode replacement character)-ээр сольж, өгөгдлийг эвддэг байв.
  • Давхардсан түлхүүрүүд (Duplicate Keys): Хэрэв JSON объект дотор нэг түлхүүр давхардсан байвал v1 алдаа заалгүй сүүлийнхийг нь авдаг байсан нь API аюулгүй байдал, өгөгдлийн зөрчилдөөнд хүргэдэг байв.
  • Санах ойн хуваарилалт ба гүйцэтгэл: Хуучин сан нь reflect багцыг хэт их ашиглаж, талбаруудыг том/жижиг үсэг ялгалгүй (case-insensitive) харьцуулдаг байсан тул олон тооны heap allocation үүсгэж, sonic, jsoniter, easyjson зэрэг гадны third-party сангуудаас 2-5 дахин удаан ажилладаг байв.
  • Уян хатан бус Custom Marshaler: Хэрэв та гуравдагч сангийн struct төрлийг өөрчлөх эрхгүй бол түүнд зориулж custom marshal/unmarshal логик бичихэд маш төвөгтэй байсан.

Эдгээр суурь асуудлуудыг v1 дээр шууд засах боломжгүй байсан тул Go-ийн нийгэмлэг анхнаасаа цоо шинэ архитектур бүтээхээр шийдсэн нь энэ юм.


2. Шинэ Архитектур: Синтакс ба Семантикийн салгалт

encoding/json/v2 шинэчлэлийн хамгийн том уран шийдэл бол serialization-ийг хоёр тусдаа түвшинд хуваасан явдал юм:

  1. encoding/json/jsontext (Синтакс түвшин): Энэ сан нь JSON грамматикийг шалгах, tokenize хийх, streaming byte урсгалыг боловсруулах үүрэгтэй. Энэ түвшинд ямар ч Go struct байхгүй, зөвхөн JSON token (BeginObject, String, Number, EndObject гэх мэт)-уудтай ажилладаг. Ингэснээр allocation бараг хийлгүйгээр асар том JSON файлыг санах ойд бүрэн ачаалахгүйгээр унших боломжтой болсон.
  2. encoding/json/v2 (Семантик түвшин): jsontext-ийн үүсгэсэн token урсгалыг Go-ийн өгөгдлийн төрлүүд (struct, map, slice) рүү хөрвүүлэх (Marshal/Unmarshal) бизнес логикийг хариуцна.

Энэхүү салгалт нь кодын цэвэр байдлыг хангахын зэрэгцээ хөрвүүлэлтийн шат бүрийг тус тусад нь оновчлох боломж олгосон юм.


3. Хөгжүүлэгчдийн амьдралыг хөнгөвчлөх шинэ боломжууд

Шинэ v2 сан нь өдөр тутмын хөгжүүлэлтэд дараах бодит давуу талуудыг авчирч байна:

Functional Options болон Илүү цэвэр API

Өмнө нь гоё хэлбэржүүлсэн JSON гаргахын тулд тусад нь json.MarshalIndent() функц ашигладаг байсан. Одоо бүх зүйл нэгдсэн функционал параметрийн бүтэцтэй болсон:

import "encoding/json/v2"
import "encoding/json/jsontext"

// Нэгдсэн тохиргоотойгоор хөрвүүлэх
data, err := json.Marshal(user, 
    jsontext.WithIndent("  "), 
    jsontext.AllowInvalidUTF8(false),
)

Шууд тодорхойлох боломжтой Custom Serializer (MarshalFunc)

Хамгийн их хүлээгдсэн боломжуудын нэг бол json.MarshalFunc юм. Та тухайн төрөл дээр MarshalJSON() интерфэйс заавал хэрэгжүүлэлгүйгээр, дуудлага хийх үедээ inline байдлаар хэрхэн сериализаци хийхийг зааж өгөх боломжтой болсон:

opts := json.WithMarshalers(
    json.MarshalFunc(func(t time.Time) ([]byte, error) {
        return []byte(`"` + t.Format("2006-01-02") + `"`), nil
    }),
)
data, err := json.Marshal(report, opts)

Алдааны дэлгэрэнгүй тайлан (Error Context)

Хуучин санд хэдэн мянган мөр бүхий нарийн нийлмэл JSON парс хийхэд json: cannot unmarshal string into Go value of type int гэсэн ганц өгүүлбэр гарч, аль түлхүүр дээр ямар алдаа гарсныг олоход там болдог байв. Харин v2 нь JSON доторх нарийн зам (жишээ нь: users[12].address.zip_code), яг хэд дэх мөр, хэд дэх баганад алдаа гарсныг тодорхой зааж өгдөг болсон.

Хурд ба Санах ойн хэмнэлт

Анхдагчаар struct талбаруудыг яг таг тохирох нэрээр (case-sensitive) харьцуулдаг болсноор болон ухаалаг компиляторын кэш ашигласнаар зарим төрлийн Unmarshal үйлдлийн гүйцэтгэл 1.5 дахин, зарим тохиолдолд 10 дахин хурдассан байна.


4. Хуучин системүүдээ яаж шилжүүлэх вэ?

Go-ийн үндсэн багийн гаргасан хамгийн ухаалаг шийдэл нь:

  1. Хуучин encoding/json өөрчлөгдөөгүй: Таны одоогийн кодууд ямар ч засваргүйгээр хуучин v1 импортоор хэвийн ажилласаар байх болно.
  2. v1-ийн суурь нь v2 болсон: Go 1.27-оос эхлэн стандарт encoding/json сангийн дотоод хөдөлгүүрийг v2-ийн үндсэн дээр шинэчлэн бичсэн тул та юу ч өөрчлөхгүй байсан ч хуучин API тань цаанаа автоматаар илүү хурдан, аюулгүй ажиллаж эхэлнэ.

Хэрэв та шинэ боломжууд, хатуу UTF-8 шалгалт, уян хатан options-ийг ашиглахыг хүсвэл ердөө импортоо шинэчилж эхлэхэд л хангалттай:

import "encoding/json/v2"

Дүгнэлт

Өнгөрсөн жилүүдэд Go-ийн стандартын JSON удаан, хатуу тул олон компаниуд системдээ sonic эсвэл jsoniter зэрэг гуравдагч сангуудыг хүчээр оруулж ирж, Cgo эсвэл unsafe assembly ашиглахаас өөр аргагүйд хүрдэг байв.

encoding/json/v2 албан ёсоор гарч ирснээр Go хөгжүүлэгчид гуравдагч сангуудаас хараат бус болж, илүү аюулгүй, стандарт нийцтэй бөгөөд хурдан JSON боловсруулалтыг эх хэлнийхээ стандарт сангаас шууд хүртэх боломж бүрдлээ. Шинэ микросервисүүдээ төлөвлөхдөө v2 руу зоригтой шилжихийг зөвлөж байна!

Эх сурвалж: The Go Blog: A new Go API for JSON (go.dev)

Сэтгэгдэл

Ачаалж байна...