专栏首页Go语言指北Go高阶指南04,struct 实现原理

Go高阶指南04,struct 实现原理

Go 语言中没有像类的概念,但是可以通过结构体 struct实现面向对象编程。struct 结构体的一些基础使用可以看下之前的文章--结构体和接口的使用传送门

本文主要介绍下 struct 在声明时可以附带的 TagTag 用来对字段做标记,主要用于反射场景,reflect 包提供了用来操作 Tag 的方法。

Tag 的本质

Tag 规则

Tag本身是一个字符串,它是 「以空格分隔的 key:value 对」

  • key : 必须是非空字符串,不能包含控制字符、空格、引号、冒号
  • value : 以双引号标记的字符串
  • 注意 :冒号前后不能有空格
type Person struct { 
  Name string `key1:"value1" key2:"value2"` //名字
  Age uint `key3:"value3"`//年龄
}

Tag 是 Struct 的一部分

Go 是如何管理 struct 字段的?如下是 reflect 包中的类型声明,部分无关代码已省略:

// A StructField describes a single field in a struct.
type StructField struct {
// Name is the field name.
Name string
...
Type Type // field type
Tag StructTag // field tag string
...
}

type StructTag string

可见,一个结构体成员的结构中包含了 StructTag,其本身是一个 string。所以说 Tag 其实是结构体字段的一部分。

获取 Tag

StructTag 提供了 Get(key string) string 方法获取 Tag 。示例:

package main

import (
  "reflect"
  "fmt"
)

type Person struct { 
  Name string `key1:"value1" key2:"value2"` 
  Age uint `key3:"value3"`
}

func main() {
  s := Person{}
  st := reflect.TypeOf(s)
  fieldA := st.Field(0)
  fmt.Printf("key1:%v\n", fieldA.Tag.Get("key1"))
  fmt.Printf("key2:%v\n", fieldA.Tag.Get("key2"))
  
  fieldB := st.Field(1)
  fmt.Printf("key3:%v\n", fieldB.Tag.Get("key3"))
}

运行结果:

key1:value1
key2:value2
key3:value3

Tag 存在意义

❝使用反射可以动态的为结构体成员赋值,通过 Tag 可以决定赋值的动作。例如官方的 encoding/json 包,使用 Tag 将一个 JSON 数据 Unmarshal 进一个结构体。基于 struct 的 tag 特性,才有了 json、orm 等应用,使用 tag,常见的是处理 JSON数据解析、ORM映射等。 ❞

本文分享自微信公众号 - 微客鸟窝(gophpython),作者:有码无尘

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Go高阶指南02,slice 实现原理

    slice 切片,因为其可以方便的进行扩容、传递等,在实际应用中比数组更加灵活。切片的一些基础使用可以看下之前的文章,传送门。

    微客鸟窝
  • Go高阶指南05,iota 实现原理

    我们知道,iota 常用于 const 表达式中,它的值是从 0 开始,每增加一行,iota 值 +1。

    微客鸟窝
  • Go高阶指南06,string 实现原理

    源代码中 src/builtin/builtin.go string 的描述如下:

    微客鸟窝
  • Go高阶指南09,select 实现原理

    select 是 GO 语言中用来提供 IO 复用的机制,它可以检测多个 chan 是否 ready(可读/可写)。

    微客鸟窝
  • Go高阶指南07,一文搞懂 defer 实现原理

    defer 语句用于延迟函数的调用,使用 defer 关键字修饰一个函数,会将这个函数压入栈中,当函数返回时,再把栈中函数取出执行。

    微客鸟窝
  • Go高阶指南10,一文搞懂 range 实现原理

    range 是 Go 语言用来遍历的一种方式,它可以操作数组、切片、map、channel 等。

    微客鸟窝
  • Go高阶指南14,内存的分配原理

    Go 中实现的内存分配器,简单的说就是维护了一大块全局内存,每个线程(Go 中的 P)维护一小块的私有内存,当私有内存不足时再向全局申请。内存分配与 GC(垃圾...

    微客鸟窝
  • Golang学习笔记之方法(method)

    一个方法只是一个函数,它有一个特殊的接收者(receiver)类型,该接收者放在 func 关键字和函数名之间。接收者可以是结构体类型或非结构体类型。可以在方法...

    李海彬
  • PHP转Go速学手册

    整理了一份简要的手册,帮助大家高效的上手Go语言,主要是通过对比PHP和Go的不同点来强化理解,内容主要分为以下四部分:

    用户1093396
  • golang学习之go简单博客应用

    先说说golang的语法吧,个人觉得有以下特点: 简洁,不管是变量、方法声明,还是代码编写,均十分简洁,效率也比较高 非纯粹面向对象,但是go的struct类似...

    用户1141560
  • go踩坑指南:修改slice里的struct类型的元素不生效?

    slice数据结构里,包含指向底层array的指针。slice作为参数传递时,实际是创建了一个新的slice对应,同时将原slice对应的array指针copy...

    hugo_lei
  • 我的书单

    songleo
  • Go编程模式 - 2.基础编码下

    然而现实情况并没有那么理想,实际项目中用得最频繁,还是自定义的2006-01-02 15:04:05

    junedayday
  • GORM V2 模型定义、约定、标签

    使用 GORM 操作数据库,需要了解 GORM 的约定和字段标签提供的约束。尽量遵循 GORM 已有的约定,但是如果约定不符合需求,也可以自定义配置,从而改变已...

    frank.
  • TB一周萃选第3期

    ? 一 一周文章精粹 01 Go初学者的类型系统入门 对于Go初学者而言,尤其是对那些从OO语言转到Go的开发者,在他们大脑中根深蒂固的OO type hie...

    企鹅号小编
  • Go高阶11,手摸手带你深入了解 Mutex 实现原理

    互斥锁是对于并发程序的共享资源进行访问控制的主要手段,之前在介绍并发的时候已经对互斥锁的使用进行过介绍:并发控制,同步原语 sync 包

    微客鸟窝
  • Go高阶12,手摸手带你深入了解 RWMutex 实现原理

    之前我们介绍了互斥锁 Mutex,今天再来介绍下 RWMutex,即读写锁。读写锁是对 Mutex 的改进,在程序中,如果存在读操作多,写操作少的场景,使用 R...

    微客鸟窝
  • 学会用Go解析复杂JSON的思路

    Go语言自带的encode/json包提供了对JSON数据格式的编码和解码能力。之前的文章《如何控制Go编码JSON数据格式的行为》已经介绍了编码JSON时常见...

    KevinYan
  • Go 数据存储篇(二):通过 JSON 格式存取文本数据

    内存存储性能虽好,但是无法持久化存储,并且容量也是有限的,要将大块数据永久保存起来,还是需要借助文件系统和数据库。我们先来看文件存储。

    学院君

扫码关注云+社区

领取腾讯云代金券