[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 - ในโค้ดก็แค่ประกาศตัวแปร
vtypeTตาม 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
}