前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言之旅:Struct Tag的介绍及用法

Go语言之旅:Struct Tag的介绍及用法

原创
作者头像
杨子翔 josonyang
发布2019-08-31 00:58:33
5.9K0
发布2019-08-31 00:58:33
举报
文章被收录于专栏:子翔的专栏子翔的专栏

前言

在学习之初我们会发现创建一个struct来表示一个model是很正常的事情,特别是在序列化json的时候,在这个学些过程中我们会发现一个内容就是跟在每个struct成员后面的用单引号标示的内容,我们称之为Struct Tag,它其实有很灵活的用途,但它的用途可以归纳为标记和扩展。

正题

为了很好的理解Tag的一些用法,将从最原理的一些部分开始,比如它是怎么定义的,怎么工作的,怎么使用的,到最后我们要如何去用。其中我会拿开源项目gorm 来做事例,因为ORM最重要的部分影射和定义就是靠Tag来完成的

Struct Tag的组成部分

Struct Tag是存在于Struct下面成员的附加属性,它的定义永远都是以key-value的形式出现的,多个定义的情况下以空格分割

Struct Tag的例子
Struct Tag的例子

在StructTag的应用中,使用最多的就是json的序列化了,序列化的包会读取tag内容,对json结果进行重命名输出,那么它是怎么读取到的呢?我们需要先了解这个Tag在整个语言段落处于什么层次。

读取并处理Tag的内容

解析方式
解析方式

如果直接拿到了这串文本我们可以这样做

代码语言:txt
复制
package main

import (
	"fmt"
	"reflect"
)

func main() {
    // 使用reflect.StructTag解析这段文本的tag内容
	tag := reflect.StructTag(`json:"foo,omitempty" xml:"foo"`)
    // 直接使用Get获取json定义
	value := tag.Get("json")
	fmt.Printf("value: %q\n", value)
}

比如定义了一个车辆的model,给它增加了一些json的tag项

代码语言:txt
复制
type Vehicle struct {
	ID             int    `json:"id"`
	CityName       string `json:"city_name"`
	Provider       string `json:"provider"`
	PlateNumber    string `json:"plate_number"`
	MaxPeople      int64  `json:"max_people"`
	PowerType      string `json:"power_type"`
}

通过reflect反射机制也可以获取到这个结构体的tag内容,比如以下代码

代码语言:txt
复制
reflectType := reflect.ValueOf(Vehicle{}).Type()
	fmt.Printf("fields number: %v\n", reflectType.NumField())

	for i := 0; i < reflectType.NumField(); i++ {
		fmt.Printf("%v", reflectType.Field(i).Name)
		fmt.Printf("  tag:%v\n", reflectType.Field(i).Tag.Get("json"))
	}

执行过后的结果,清清楚楚的取得了tag的内容

image.png
image.png

实际应用-GORM

实际应用场景中,我们除了经常对json序列化用到以外,还经常在使用开源组件中遇到,比如说GORM,它是一个典型的应用场景,因为它需要对实体中的每一项进行额外定义,以达到映射和功能标记的作用。虽然查看它的官方文档,我们可以很详细的知道用法,我们也可以直接跳到GORM的Github仓库去了解它是如何运作的。

进入model_struct.go文件,在GetModelStruct方法中我们可以看到

代码语言:txt
复制
    //通过反射获取类型定义
reflectType := reflect.ValueOf(scope.Value).Type()
	for reflectType.Kind() == reflect.Slice || reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}
	
	.......

    // 对每一项进行tag的获取和逻辑
    // Get all fields
	for i := 0; i < reflectType.NumField(); i++ {
		if fieldStruct := reflectType.Field(i); ast.IsExported(fieldStruct.Name) {

		......

		field.TagSettingsGet("PRIMARY_KEY")
		......
		if value, ok := field.TagSettingsGet("COLUMN"); ok {
			field.DBName = value
		} else {
			field.DBName = ToColumnName(fieldStruct.Name)
		}
		......

整个GORM的核心就在于根据数据库映射的model,然后再根据定义好的内部结构来拼接sql达到ORM的效果。这里跟dotnet里面的Attribute的作用类似,我们做了一些Attribute也可以通过反射获取信息。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正题
    • Struct Tag的组成部分
      • 读取并处理Tag的内容
        • 实际应用-GORM
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档