[Go] สร้างฟังก์ชัน unmarshal json.RawMessage แบบ generic type และเช็คค่า null
มีเคสต้องกำหนดค่า request body field นึง ให้เป็น type json.RawMessage
ไปก่อนแล้วค่อยไปเช็คเงื่อนไขอีกทีว่าจะ unmarshaling ไปใส่ตัวแปร type ไหน แต่ก็อยากรู้ด้วยว่าค่าใน json.RawMessage
เป็น null
value ของ JSON หรือไม่ เลยได้ลองสร้างฟังก์ชันที่เป็น generic รองรับการ parse ค่าจาก json.RawMessage
เป็น type ใดๆดูพร้อมกับ return flag เพื่อบอกว่าเป็น null
หรือไม่
โค้ดเป็นแบบนี้
func rawMessageToValue[T any](raw json.RawMessage) (T, bool, error) {
var v T
if string(raw) == `null` {
return v, true, nil
}
err := json.Unmarshal(raw, &v)
return v, false, err
}
- มี type parameter T มี constraint เป็น any คือเป็น type อะไรก็ได้
- รับค่า
raw
เป็นjson.RawMessage
- และ return ออกไป 3 ค่าซึ่งก็คือ
T
เองหลังจาก unmarshaling แล้ว, ค่าbool
เพื่อบอกว่าเป็นnull
หรือไม่ และerror
ถ้าเกิดมี error ตอน unmarshaling - ในโค้ดก็แค่ประกาศตัวแปร
v
typeT
ตาม type parameter - เช็คว่า
raw
มีค่าเป็นnull
หรือเปล่าโดยแปลงเป็นstring
ก่อนแล้วค่อยเทียบกับstring
ค่าnull
ถ้าใช่ก็ returnv
ออกไปเลยแบบไม่ต้องทำอะไร พร้อมค่าที่สองเป็นtrue
และ error เป็นnil
- ถ้าไม่ใช่ก็แค่เรียก
json.Unmarshal(raw, &v)
แล้วreturn v, false, err
เพื่อบอกว่า Unmarshal ได้อะไรและบอกว่าไม่เป็นnull
นะ
เวลาใช้งานเราก็สามารถเช็คจากค่าที่สองได้ว่าเป็น null
หรือเปล่า ถ้าไม่ใช่ก็เช็คว่า error
หรือเปล่า ถ้าไม่ก็เอา ค่าแรกที่ return กลับไปใช้งานได้เลย เช่น
func main() {
raw := json.RawMessage("null")
n, isNull, err := rawMessageToValue[int](raw)
if isNull {
fmt.Println(isNull)
} else if err != nil {
fmt.Println(err)
} else {
fmt.Println(n)
}
// Output:
// true
}
func main() {
raw := json.RawMessage("10")
n, isNull, err := rawMessageToValue[int](raw)
if isNull {
fmt.Println(isNull) // false
} else if err != nil {
fmt.Println(err)
} else {
fmt.Println(n)
}
// Output:
// 10
}
func main() {
raw := json.RawMessage(`"Hello, World"`)
str, isNull, err := rawMessageToValue[string](raw)
if isNull {
fmt.Println(isNull) // false
} else if err != nil {
fmt.Println(err)
} else {
fmt.Println(str)
}
// Output:
// Hello, World
}
func main() {
raw := json.RawMessage(`"2023-03-18T16:15:00.000+07:00"`)
t, isNull, err := rawMessageToValue[time.Time](raw)
if isNull {
fmt.Println(isNull) // false
} else if err != nil {
fmt.Println(err)
} else {
fmt.Println(t)
}
// Output:
// 2023-03-18 16:15:00 +0700 +0700
}