- Published on
การกำหนด Default Value ให้กับ Struct ในภาษา Go
- Authors
- Name
- Somprasong Damyos
- @somprasongd
การกำหนด Default Value ให้กับ Struct ในภาษา Go
ใน Go ไม่มีการกำหนด default value ให้กับ struct โดยตรง เมื่อประกาศ struct จะไม่มีค่า default สำหรับ field ใดๆ ใน struct นั้นๆ ถ้าต้องการกำหนดค่า default สำหรับ struct ใน Go สามารถทำได้โดยใช้วิธีการสร้างฟังก์ชั่นที่คืนค่า struct พร้อมกับกำหนดค่า default สำหรับ field ใน struct นั้น ๆ เช่น
type Person struct {
Name string
Age int
Address string
}
func NewPerson() Person {
return Person{
Name: "John Doe",
Age: 30,
Address: "Unknown",
}
}
ในตัวอย่างข้างต้นฟังก์ชัน NewPerson
จะคืนค่า struct Person
พร้อมกับกำหนดค่า default สำหรับ field ทั้ง 3 ตัว คือ
Name
ใช้ค่า"John Doe"
Age
ใช้ค่า30
Address
ใช้ค่า"Unknown**"
ซึ่งสามารถใช้งานได้โดยการเรียกใช้งานฟังก์ชัน NewPerson
แทนการประกาศ struct Person
โดยตรง ดังนี้
package main
func main() {
p := NewPerson()
fmt.Println(p.Name) // Output: "John Doe"
fmt.Println(p.Age) // Output: 30
fmt.Println(p.Address) // Output: unknown
}
สร้าง tag default
เราสามารถสร้าง tag ใหม่ขึ้นมา ตัวอย่างเช่น default
เพื่อใช้กำหนดค่า default ให้กับ field ใน struct ได้ ดังนี้
type Person struct {
Name string `default:"John Doe"`
Age int `default:"30"`
Address string `default:"Unknown"`
}
และใช้ความรู้เรื่อง reflect เข้ามาช่วยในการดึงค่าจาก tag ออกมา ดังน้ี
func SetDefaults(obj interface{}) {
// ใช้ reflect ในการดึงค่าของ struct และตรวจสอบประเภทของ field
val := reflect.ValueOf(obj).Elem()
typ := val.Type()
// วนลูปตามจำนวน field ที่มีใน struct
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
// ตรวจสอบว่า field นั้นมีค่าที่ถูกต้องหรือไม่
if !field.IsValid() {
continue // ข้ามไปยัง field ถัดไป
}
// ถ้าเป็น struct ให้เรียกฟังก์ชัน SetDefaults ต่อที่ field นั้นๆ
if field.Kind() == reflect.Struct {
SetDefaults(field.Addr().Interface())
continue // ข้ามไปยัง field ถัดไป
}
// ดึงค่า tag "default" ของ field นั้นๆ
tag := typ.Field(i).Tag.Get("default")
if tag == "" {
continue // ข้ามไปยัง field ถัดไป
}
// ตรวจสอบประเภทของ field และกำหนดค่า default ตาม tag ที่ระบุ
setDefault(field, tag)
}
}
func setDefault(field reflect.Value, tag string) {
// ตรวจสอบประเภทของ field และกำหนดค่า default ตาม tag ที่ระบุ
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
// ตรวจสอบว่า tag ที่ระบุเป็นตัวเลขที่สามารถแปลงเป็น int ได้
if i, err := strconv.ParseInt(tag, 10, 64); err == nil {
field.SetInt(i) // กำหนดค่า default เป็นค่า int ที่แปลงมาได้
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// ตรวจสอบว่า tag ที่ระบุเป็นตัวเลขที่สามารถแปลงเป็น uint ได้
if i, err := strconv.ParseUint(tag, 10, 64); err == nil {
field.SetUint(i) // กำหนดค่า default เป็นค่า uint ที่แปลงมาได้
}
case reflect.Float32, reflect.Float64:
// ตรวจสอบว่า tag ที่ระบุเป็นตัวเลขที่สามารถแปลงเป็น float ได้
if f, err := strconv.ParseFloat(tag, 64); err == nil {
field.SetFloat(f) // กำหนดค่า default เป็นค่า float ที่แปลงมาได้
}
case reflect.Bool:
// ตรวจสอบว่า tag ที่ระบุเป็น "true" หรือ "false"
if strings.ToLower(tag) == "true" {
field.SetBool(true) // กำหนดค่า default เป็น true
} else if strings.ToLower(tag) == "false" {
field.SetBool(false) // กำหนดค่า default เป็น false
}
case reflect.String:
field.SetString(tag) // กำหนดค่า default เป็นค่า string ที่ระบุใน tag
default:
// ไม่รองรับชนิดข้อมูล
}
}
ตัวอย่างการใช้งาน
package main
func main() {
p := Person{}
SetDefaults(&p)
fmt.Printf("%+v\n", p)
}