Golang Program to Use Field Tags in the Definition of Struct Type


In Go programming language, field tags are metadata that can be attached to the fields of a struct type. These tags provide additional information about the field such as its name, data type, validation rules, etc. Field tags are used extensively in many Go libraries and frameworks, including database and web application frameworks.

In this article, we will explore how to use field tags in the definition of a struct type in Go programming language. We will also discuss some common use cases of field tags and their benefits.

What is a Struct Type in Go?

A struct type is a user-defined composite type that represents a collection of fields with different data types. Each field in the struct has a name and a data type. Structs are used to represent complex data structures such as user accounts, database records, etc.

Using Field Tags in Struct Types

To use field tags in the definition of a struct type, we need to define the tags as a string literal after the field name. For example, consider the following struct definition −

type Person struct {
   Name string `json:"name"`
   Age  int    `json:"age"`
}

In this example, we have defined a struct type named "Person" with two fields: "Name" and "Age". We have also added field tags to each field. The field tag for the "Name" field is "json:"name"", which indicates that this field should be serialized as "name" when converting the struct to JSON format. Similarly, the field tag for the "Age" field is "json:"age"", which indicates that this field should be serialized as "age".

Golang Program to Use Field Tags in Structs

Example

Now, let's write a Golang program to use field tags in the definition of struct type −

package main

import (
   "fmt"
   "reflect"
)

type User struct {
   Name     string `json:"name" xml:"name"`
   Age      int    `json:"age" xml:"age"`
   Location string `json:"location" xml:"location"`
}

func main() {
   user := User{
      Name:     "John Doe",
      Age:      30,
      Location: "New York",
   }

   // Print the field tags for each field
   t := reflect.TypeOf(user)
   for i := 0; i < t.NumField(); i++ {
      field := t.Field(i)
      fmt.Printf("%s: %s\n", field.Name, field.Tag)
   }
}

In this program, we define a struct type User with three fields: Name, Age, and Location. We add field tags to each field using the json and xml keys. We then create a new instance of the User struct and initialize its fields with some sample values.

To print the field tags for each field in the User struct, we use the reflect package to get the type of the User struct and loop through its fields using the NumField() and Field() methods. We then print the name and tag of each field using the Name and Tag fields of the reflect.StructField type.

Output

This output shows the field name and its corresponding field tags.

Name: json:"name" xml:"name"
Age: json:"age" xml:"age"
Location: json:"location" xml:"location"

Example

Here is another example −

package main

import (
   "encoding/json"
   "fmt"
   "reflect"
)

type Person struct {
   Name    string `json:"name" validate:"required"`
   Age     int    `json:"age" validate:"required,gte=18"`
   Email   string `json:"email" validate:"required,email"`
}

func main() {
   p := Person{Name: "John", Age: 20, Email: "john@example.com"}

   // validate struct fields
   if err := validate(p); err != nil {
      fmt.Println(err)
   }

   // convert struct to JSON
   jsonData, _ := json.Marshal(p)
   fmt.Println(string(jsonData))
}

func validate(s interface{}) error {
   value := reflect.ValueOf(s)

   if value.Kind() == reflect.Ptr {
      value = value.Elem()
   }

   typeOf := value.Type()

   for i := 0; i < value.NumField(); i++ {
      field := value.Field(i)
      tag := typeOf.Field(i).Tag.Get("validate")

      if tag == "required" {
         if field.Kind() == reflect.String {
            if field.Len() == 0 {
               return fmt.Errorf("%s is required", typeOf.Field(i).Name)
            }
         } else if field.Kind() == reflect.Int {
            if field.Int() == 0 {
               return fmt.Errorf("%s is required", typeOf.Field(i).Name)
            }
         } else {
            return fmt.Errorf("unsupported field type")
         }
      } else if tag != "" {
         // handle other validation rules here
      }
   }
   return nil
}

Output

{"name":"John","age":20,"email":"john@example.com"}

In this example, we have defined the same "Person" struct type as before, but we are not using the "validator" package anymore. Instead, we have defined a custom "validate" function that uses reflection to loop through the struct fields and validate them based on the field tags.

The "validate" function takes an interface{} parameter, which allows us to pass any struct type to it. It uses reflection to determine the type of the struct and loop through its fields. For each field, it checks the "validate" tag and performs the appropriate validation based on the tag value.

In this example, we are only checking for the "required" validation rule, but you could easily add more validation rules by extending the "validate" function.

After validating the struct fields, the program uses the "json" package to convert the struct to JSON format and prints it out to the console.

Common Use Cases of Field Tags

Field tags can be used in many different ways depending on the requirements of the application. Some common use cases of field tags include −

  • Serialization and Deserialization − Field tags are commonly used to specify the serialization and deserialization rules for struct fields. For example, the "json" tag is used to specify the field names when converting a struct to or from JSON format.

  • Validation − Field tags can also be used to specify validation rules for struct fields. For example, the "validate" tag can be used to specify a regular expression pattern that the field value must match.

  • Database Mapping − Field tags can be used to specify the mapping between struct fields and database columns. For example, the "db" tag can be used to specify the column name in a database table.

Benefits of Using Field Tags

Using field tags in struct types provides several benefits, including −

  • Improved Code Readability − Field tags can help improve the readability of the code by providing additional information about the purpose of each field.

  • Reduced Boilerplate Code − Field tags can help reduce the amount of boilerplate code required to serialize, deserialize, and validate struct fields.

  • Flexibility − Field tags provide a flexible way to specify metadata for struct fields. This allows developers to customize the behavior of the struct without modifying its underlying data structure.

Conclusion

In this article, we have discussed how to write a Golang program to use field tags in the definition of struct type. We have explained what field tags are and how they can be used to provide metadata about the fields of a struct. By following the steps provided, you can learn how to use field tags in your own struct definitions and take advantage of their many benefits.

Updated on: 20-Apr-2023

242 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements