[Golang] ข้อควรระวัง map[string]interface{}
กลับมาอีกครั้งกับ Golang หลังจากหันไปทำ flutter อยู่ 3 เรื่อง พอดีตอนทำงานเจอ case ของการใช้ map[string]interface{} อย่างหนึ่งที่อาจจะทำให้คน งงกันพอสมควร
ข้อควรระวังนั้นก็คือ!
การเปลี่ยนค่าภายใน map[string]interface{} ที่มีการซ้อนกันข้างในหลายชั้น เพื่อความเข้าใจก็คงต้องยกตัวอย่าง จำได้ไหมจากเรื่อง [Golang] How to parse JSON หัวข้อ Unstructured data เราได้ทำการใช้งาน map[string]interface{} เพื่อแปลง string JSON มาอยู่ในรูปแบบที่เราใช้ได้ง่ายโดยไม่ต้องมี struct แล้วถ้าเรามี JSON ในลักษณะนี้ละ
{
"Person": {
"Name": "BLABLA",
"Age": 23
},
"Position": "Full-Stack Developer",
"Main": "Back-End Developer"
}
จะเห็นว่ามี Person ที่เป็น Data แบบ ซ้อนเข้าไปอีกชั้น เอาละแปลงมันให้อยู่ในรูปของ map[string]interface{} ก่อน
str := `{
"Person": {
"Name": "BLABLA",
"Age": 23
},
"Position": "Full-Stack Developer",
"Main": "Back-End Developer"
}`
var result map[string]interface{}
json.Unmarshal([]byte(str), &result)
และเมื่อเราต้องการเปลี่ยนค่าด้านใน
str := `{
"Person": {
"Name": "BLABLA",
"Age": 23
},
"Position": "Full-Stack Developer",
"Main": "Back-End Developer"
}`
var result map[string]interface{}
json.Unmarshal([]byte(str), &result)
fmt.Println("result ========> ", result)
if p, ok := result["Person"].(map[string]interface{}); ok {
fmt.Println("p ========> ", p)
p["Name"] = "Change Name"
p["Age"] = 24
fmt.Println("p ========> ", p)
}
fmt.Println("result ========> ", result)
จาก Code ด้านบนนั้นแสดงถึงการเข้าถึงค่าเพื่อแก้ค่าด้านในทุกอย่างดูปกติใช่ไหมละครับ ผลลัพท์ที่ได้ก็จะเป็นในลักษณะแบบนี้
จะเห็นว่า result ในตอนแรกนั้นก็จะเหมือนกับ Input ตั้งตอนของเรานั้นละ จากนั้นเราก็ทำเปลี่ยนค่า Name “BLABLA” เป็น “Change Name” และ ค่า Age 23 เป็น 24 result สุดท้ายค่าก็เปลี่ยนไปอย่างที่เราต้องการ
แต่! ถ้าเราต้องการเก็บค่า Person ให้กับอีกตัวแปรที่เราสร้างไว้แล้วทำการเปลี่ยนค่ามัน
str := `{
"Person": {
"Name": "BLABLA",
"Age": 23
},
"Position": "Full-Stack Developer",
"Main": "Back-End Developer"
}`
var result map[string]interface{}
json.Unmarshal([]byte(str), &result)
fmt.Println("result ========> ", result)
var person map[string]interface{}
if p, ok := result["Person"].(map[string]interface{}); ok {
person = p
}
person["Name"] = "LazyDev"
person["Age"] = 25
fmt.Println("person ========> ", person)
fmt.Println()
fmt.Println("result ========> ", result)
fmt.Println()
จะเกิดเหตุการณ์แบบนี้
เห็นอะไรไหมครับ เมื่อเราทำการเปลี่ยนค่า person ซึ่งทั่วๆ ไป เราก็คงคิดว่าเป็นอีกตัวแปรนึงที่ไม่ได้เกี่ยวข้องกับตัวแปร result แล้ว แต่กลับกลายเป็นว่าเมื่อเราเปลี่ยนค่า Person มันส่งผลกระทบถึง result ด้วย
โดยในกรณีนี้เนี่ยต้องระวังหากคุณเลือกที่จะส่งค่า person เข้าไปทำที่ฟังก์ชั่นอื่นๆ ใดแล้วคิดว่า result นั้นค่าไม่ได้เปลี่ยนไปเป็นอย่างเดิมแล้วเกิดการคำนวนผิดในกรณีต่างๆ
ดู Code ทั้งหมดได้ที่ Github
เจอกันใหม่ Blog หน้า Bye bye