当前位置: 首页 > article >正文

GO语言入门-反射5(结构体的Tag)

12.5 结构体的 Tag

在定义结构体类型时,可以在字段后面加上一个字符串,称为 Struct Tag。Tag 主要用来补充附加信息。

Tag 由多个 key - value 构成,并以空格来分隔,key 和 value 之间用英文的冒号分隔。其格式如下:

key1:"value1" key2:"value2" key3:"value3"……

value 必须放在一对双引号中。为了避免字符转义,Tag 字符串可以用 “`” 字符来包装,就像下面这样:

key1:"value1" key2:"value2" key3:"value3"

在 reflect 包中定义了 StructTag 类型,表示 Tag 实例。

type StructTag string

从定义上可以看出,StructTag 是以字符串为基础的新类型。为了便于访问 Tag 中的条目,StructTag 类型提供以下两个方法:

  1. Get:根据 key 获取对应的 value。
  2. Lookup:根据 key 查找 value。如果找到,返回值 ok 为 true,并将结果存到 value 中;如果找不到,则 ok 为 false。

下面的示例演示了如何通过字段的 Tag 来为用户名和密码设置限制条件。当程序对用户信息进行检查时,会从 Tag 中读出相应的限制条件,如果所设置的用户名和密码与限制条件不符,则会输出错误信息。

步骤 1: 定义 User 结构体

type User struct {Username string `maxlen:"10"`Password string `minlen:"8" mask:"* "`
}

在 Username 字段的 Tag 中,maxlen 表示用户名的最大长度为 10 个字符,同样,在 Password 字段的 Tag 中,minlen 表示密码的最小长度为 8 个字符。mask 指定密码的掩码,掩码用于在屏幕输出密码时隐藏真实的密码内容,输出形如 “*****” 的文本。

步骤 2: 定义 validateUser 函数,用于检查用户名和密码是否满足限制条件

func validateUser(u User) {var typofUser = reflect.TypeOf(u)var valofUser = reflect.ValueOf(u)// 读出 TagtagUn := typofUser.Field(0).TagtagPwd := typofUser.Field(1).Tag// 解析用户名最大长度maxLenofUn, _ := strconv.ParseInt(tagUn.Get("maxlen"), 10, 0)// 解析密码最小长度minLenofPwd, _ := strconv.ParseInt(tagPwd.Get("minlen"), 10, 0)// 读取两个字段的值var usrName = valofUser.Field(0).String()var pssWd = valofUser.Field(1).String()// 开始验证unLen := utf8.RuneCountInString(usrName)pwdLen := utf8.RuneCountInString(pssWd)if unLen > int(maxLenofUn) {fmt.Printf("用户名 %s 长度超过 %d\n", usrName, maxLenofUn)return}if pwdLen < int(minLenofPwd) {// 获取密码掩码maskChar := tagPwd.Get("mask")// 生成类似"* * * * * * * *"的密码字符串displayPwd := strings.Repeat(maskChar, pwdLen)fmt.Printf("密码 %s 的长度不符,至少需要 %d 个字符\n", displayPwd, minLenofPwd)return}fmt.Println("用户信息符合要求")
}

步骤 3: 创建第一个 User 实例,并为字段赋值,然后调用 validateUser 函数进行检查

var u1 User
u1.Username = "jk_056546595xlase"
u1.Password = "65656565656"
validateUser(u1)

u1 对象设置的用户名过长,检查结果为:

用户名 jk_056546595xlase 长度超过10

步骤 4: 创建第二个 User 实例,并为字段赋值,然后进行检查

var u2 User
u2.Username = "Jack"
u2.Password = "321"
validateUser(u2)

u2 对象的密码长度不符合要求,检查结果为:

密码 *** 的长度不符,至少需要8个字符

步骤 5: 创建第三个 User 实例,并为字段赋值,然后进行检查

var u3 User
u3.Username = "Alice"
u3.Password = "UUI9ocg210359m82"
validateUser(u3)

u3 对象完全满足限制条件的要求,所以顺利通过检查。

补充:

在Go语言里,结构体标签(Tag)是依附于结构体字段的元数据字符串,它能为字段增添额外信息,这些信息可在运行时借助反射机制读取,从而实现序列化、数据验证、数据库映射等多种功能。

代码示例

下面的示例代码会展示结构体标签在JSON序列化、数据验证以及自定义业务逻辑中的应用。

package mainimport ("encoding/json""fmt""reflect""strconv""strings"
)// User 定义用户结构体,包含多个带标签的字段
type User struct {// JSON序列化标签,指定JSON键名及忽略空值Name     string `json:"user_name,omitempty" validate:"min=3,max=20" biz:"name"`Age      int    `json:"user_age" validate:"min=18,max=100" biz:"age"`Email    string `json:"user_email" validate:"email" biz:"email"`Password string `json:"-" validate:"min=6" biz:"password"`
}// validate 自定义验证函数,根据标签规则验证结构体字段
func validate(u interface{}) error {v := reflect.ValueOf(u)if v.Kind() == reflect.Ptr {v = v.Elem()}t := v.Type()for i := 0; i < v.NumField(); i++ {field := t.Field(i)tag := field.Tag.Get("validate")if tag == "" {continue}rules := strings.Split(tag, ",")value := v.Field(i)switch value.Kind() {case reflect.String:strValue := value.String()for _, rule := range rules {parts := strings.Split(rule, "=")if len(parts) == 2 {key, val := parts[0], parts[1]switch key {case "min":min, _ := strconv.Atoi(val)if len(strValue) < min {return fmt.Errorf("%s 长度不能小于 %d", field.Name, min)}case "max":max, _ := strconv.Atoi(val)if len(strValue) > max {return fmt.Errorf("%s 长度不能大于 %d", field.Name, max)}case "email":if !strings.Contains(strValue, "@") {return fmt.Errorf("%s 不是有效的邮箱地址", field.Name)}}}}case reflect.Int:intValue := value.Int()for _, rule := range rules {parts := strings.Split(rule, "=")if len(parts) == 2 {key, val := parts[0], parts[1]switch key {case "min":min, _ := strconv.Atoi(val)if intValue < int64(min) {return fmt.Errorf("%s 不能小于 %d", field.Name, min)}case "max":max, _ := strconv.Atoi(val)if intValue > int64(max) {return fmt.Errorf("%s 不能大于 %d", field.Name, max)}}}}}}return nil
}func main() {// 创建用户实例user := User{Name:     "Alice",Age:      25,Email:    "alice@example.com",Password: "abcdef",}// 验证用户信息if err := validate(user); err != nil {fmt.Println("验证失败:", err)return}// JSON序列化data, err := json.Marshal(user)if err != nil {fmt.Println("JSON序列化失败:", err)return}fmt.Println("JSON序列化结果:", string(data))// 读取自定义业务标签t := reflect.TypeOf(user)for i := 0; i < t.NumField(); i++ {field := t.Field(i)bizTag := field.Tag.Get("biz")fmt.Printf("%s 的业务标签是: %s\n", field.Name, bizTag)}
}

运行结果如下:

JSON序列化结果: {"user_name":"Alice","user_age":25,"user_email":"alice@example.com"}
Name 的业务标签是: name
Age 的业务标签是: age
Email 的业务标签是: email
Password 的业务标签是: password

代码解释

  1. 结构体定义User结构体中的每个字段都有多个标签。json标签用于指定JSON序列化时的键名以及是否忽略空值;validate标签用于定义字段的验证规则;biz标签是自定义的业务标签。
  2. 验证函数validate函数借助反射读取结构体字段的validate标签,依据规则对字段值进行验证,若不满足规则则返回错误。
  3. JSON序列化:在main函数里,先创建User实例,调用validate函数验证用户信息,验证通过后使用json.Marshal对用户信息进行JSON序列化并输出结果。
  4. 自定义业务标签读取:通过反射读取biz标签,输出每个字段的业务标签信息。

json标签:
json:“user_name,omitempty”:意味着在进行 JSON 序列化时,Name字段会以user_name作为键名;omitempty选项表示当Name字段为空字符串时,该字段不会出现在序列化后的 JSON 数据中。
json:“-”:表示Password字段在 JSON 序列化时会被忽略。
validate标签:
validate:“min=3,max=20”:针对Name字段定义了验证规则,要求其长度在 3 到 20 个字符之间。
validate:“min=18,max=100”:为Age字段设定了验证规则,要求其值在 18 到 100 之间。
validate:“email”:要求Email字段的值必须是一个有效的邮箱地址。
validate:“min=6”:规定Password字段的长度至少为 6 个字符。
biz标签:这是自定义的业务标签,为每个字段添加了业务相关的标识,像biz:“name” 、biz:"age"等,方便在业务逻辑里进行区分和处理。

通过这个示例,你能看到结构体标签在不同场景下的强大作用,可在实际开发中依据需求灵活运用。

相关文章:

GO语言入门-反射5(结构体的Tag)

12.5 结构体的 Tag 在定义结构体类型时&#xff0c;可以在字段后面加上一个字符串&#xff0c;称为 Struct Tag。Tag 主要用来补充附加信息。 Tag 由多个 key - value 构成&#xff0c;并以空格来分隔&#xff0c;key 和 value 之间用英文的冒号分隔。其格式如下&#xff1a;…...

免费下载 | 2025电力数据资产管理体系白皮书

本文是一份关于2025年电力数据资产管理体系的白皮书&#xff0c;详细阐述了电力数据要素和数据资产管理的现状、挑战、发展进程以及电网数据资产管理体系的构建与实践。白皮书强调了数据作为生产要素的重要性&#xff0c;并提出了电网数据资产管理体系的创新模式&#xff0c;旨…...

4185 费马小定理求逆元

4185 费马小定理求逆元 ⭐️难度&#xff1a;简单 &#x1f31f;考点&#xff1a;费马小定理 &#x1f4d6; &#x1f4da; import java.util.Scanner; import java.util.Arrays;public class Main {static int[][] a;public static void main(String[] args) {Scanner sc …...

处理Excel表不等长时间序列用tsfresh提取时序特征

我原本的时间序列格式是excel表记录的&#xff0c;每一行是一条时间序列&#xff0c;时间序列不等长。 要把excel表数据读取出来之后转换成extract_features需要的格式。 1.读取excel表数据 import pandas as pd import numpy as np from tsfresh import extract_features mda…...

从keys到SCAN:Redis批量删除的进化之路

标签:Redis、批量删除、前缀匹配、性能优化 一、痛点分析:为什么需要批量删除指定前缀的键? 在 Redis 使用过程中,我们经常会遇到这样的场景: 需要对某一类数据进行清理,例如用户会话、缓存数据等,而这些数据通常以某种前缀命名(如 user:session:*、cache:data:*)。如…...

界面控件DevExpress WinForms v25.1新功能预览 - 聚焦用户体验升级

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…...

卷积神经网络(CNN)基础

目录 一、应用场景 二、卷积神经网络的结构 1. 输入层&#xff08;Input Layer&#xff09; 2. 卷积层&#xff08;Convolutional Layer&#xff09; 3. 池化层&#xff08;Pooling Layer&#xff09; 最大池化&#xff08;max_pooling&#xff09;或平均池化&#xff08;…...

Android Spotify-v9.0.36.443-arm64-Experimental Merged版

Android Spotify 链接&#xff1a;https://pan.xunlei.com/s/VONXTdIv9d4FnAiNMMliIAEJA1?pwdxt7q# Android Spotify-v9.0.36.443-arm64-Experimental Merged版 享受高达256kbps的AAC音频。...

html元素转图像之深入探索 html - to - image:功能、应用与实践

html元素转图像之深入探索 html-to-image&#xff1a;功能、应用与实践 一、引言 使用该插件 需要注意页面上的图片都能正常显示&#xff0c;否则会报错&#xff0c;或生成的图片有误&#xff0c;注意注意。 在当今数字化内容丰富多样的时代&#xff0c;将网页上的特定 HTML…...

LLM之Agent(十六)| MCP已“过时”?Google近期推出Agent2Agent 协议 (A2A)

如今&#xff0c;企业越来越多地构建和部署自主代理&#xff0c;以帮助扩展、自动化和增强整个工作场所的流程 - 从订购新笔记本电脑到协助客户服务代表&#xff0c;再到协助供应链规划。 为了最大限度地发挥代理 AI 的优势&#xff0c;这些代理能够在一个动态的、多代理的生态…...

Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification

Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification 目录 Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification`AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)`功能概述参数解释`AutoModelForSequen…...

网络安全1

一、网络安全的定义与重要性 定义 网络安全&#xff08;信息技术安全&#xff09;&#xff1a;保护计算机系统和网络免受电子攻击的技术和过程&#xff0c;包括保护个人信息和企业数据不被盗窃、破坏或非法访问。涵盖范围&#xff1a;网络设备、数据传输、系统运行安全。 重要…...

Java学习总结-端口-协议

端口号&#xff1a;一个16位的二进制&#xff0c;范围是0-65535 端口分类&#xff1a; 周知端口&#xff1a;0-1023&#xff0c;被预先定义的知名应用占用&#xff08;如&#xff1a;HTTP占用80&#xff0c;FTP占用21&#xff09; 注册端口&#xff1a;1024-49151&#xff0…...

克魔助手(Kemob)安装与注册完整教程 - Windows/macOS双平台指南

iOS设备管理工具克魔助手便携版使用全指南 前言&#xff1a;为什么需要专业的iOS管理工具 在iOS开发和设备管理过程中&#xff0c;开发者经常需要突破系统限制&#xff0c;实现更深层次的控制和调试。本文将详细介绍一款实用的便携式工具的使用方法&#xff0c;帮助开发者快速…...

✅ Ultralytics YOLO 训练(Train)时实时获取 COCO 指标(AP):2025最新配置与代码详解 (小白友好 + B站视频)

✅ YOLO获取COCO指标(4): 训练(Train)启用COCO API评估&#xff08;实时监控AP指标&#xff09;| 发论文必看&#xff01; | Ultralytics | 小白友好 文章目录 一、问题定位二、原理分析三、解决方案与实践案例步骤 1: 在 model.train() 调用中设置 save_jsonTrue步骤 2: 修改 …...

qwen-vl 实现OCR的测试

OCR 技术是数字化时代必不可少的实用工具。以前都依赖专业的公司的专业软件才能完成。成本很高。也正因为如此&#xff0c;我国纸质资料的数字化并不普及。基于大模型的ORC 也许会改变这样的现状。 文本识别&#xff0c;也称为光学字符识别 (OCR)&#xff0c;可以将印刷文本或…...

算法训练之动态规划(五)——简单多状态问题

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...

C++ 大数相加(简要版)

#include <algorithm> #include <iterator> class Solution { public:/*** 计算两个数之和* param s string字符串 表示第一个整数* param t string字符串 表示第二个整数* return string字符串*/string solve(string s, string t) {// 处理空字符串的情况&#xf…...

SVMSPro分布式综合安防管理平台-->以S3存储革新,开启智能安防新纪元

SVMSPro分布式综合安防管理平台–>以S3存储革新&#xff0c;开启智能安防新纪元 在数字化转型浪潮下&#xff0c;企业安防管理正面临海量数据存储、跨区域协同以及数据安全的严峻挑战。如何实现高效、弹性、低成本的存储扩容&#xff1f;如何确保关键录像数据万无一失&…...

KV Cache大模型推理加速功能

KV Cache KV Cache是大模型标配的推理加速功能&#xff0c;也是推理过程中&#xff0c;显存资源巨大开销的元凶之一。在模型推理时&#xff0c;KV Cache在显存占用量可达30%以上。 目前大部分针对KV Cache的优化工作&#xff0c;主要集中在工程上。比如著名的VLLM&#xff0c…...

速盾:高防CDN节点对收录有影响吗?

引言 搜索引擎收录是网站运营中至关重要的环节&#xff0c;它直接影响着网站的曝光度和流量。近年来&#xff0c;随着网络安全威胁的增加&#xff0c;许多企业开始采用高防CDN&#xff08;内容分发网络&#xff09;来保护其网站免受DDoS攻击和其他形式的网络攻击。然而&#x…...

脑科学与人工智能的交叉:未来智能科技的前沿与机遇

引言 随着科技的迅猛发展&#xff0c;脑科学与人工智能&#xff08;AI&#xff09;这两个看似独立的领域正在发生深刻的交汇。脑机接口、神经网络模型、智能机器人等前沿技术&#xff0c;正带来一场跨学科的革命。这种结合不仅推动了科技进步&#xff0c;也在医疗、教育、娱乐等…...

Linux 系统中从源码编译安装软件

以下是 Linux 系统中 从源码编译安装软件 的详细步骤和注意事项&#xff0c;帮助你掌握这一高级操作技能&#xff1a; 一、编译安装的核心流程 1. 下载源码包&#xff08;通常为 .tar.gz/.tar.bz2/.tar.xz&#xff09; 2. 解压源码包 3. 进入源码目录 4. 配置编译参数&#xf…...

docker 运行自定义化的服务-后端

docker 运行自定义化的服务-前端-CSDN博客 运行自定义化的后端服务 具体如下&#xff1a; ①打包后端项目&#xff0c;形成jar包 ②编写dockerfile文件&#xff0c;文件内容如下&#xff1a; # 使用官方 OpenJDK 镜像 FROM jdk8:1.8LABEL maintainer"ATB" version&…...

基于关键字定位的自动化PDF合同拆分

需求背景&#xff1a; 问题描述&#xff1a; 我有一份包含多份合同的PDF文件&#xff0c;需要将这些合同分开并进行解析。 传统方法&#xff08;如以固定页数作为分割点&#xff09;不够灵活&#xff0c;无法满足需求。 现有方法的不足&#xff1a; 网上找到的工具大多依赖手动…...

spring security 使用auth2.0

在 Spring Security 中集成 OAuth 2.0 可以实现安全的第三方认证和资源保护。以下是完整的配置指南和代码示例&#xff1a; 一、OAuth 2.0 核心概念 角色作用资源所有者用户&#xff08;授权访问资源的人&#xff09;客户端应用&#xff08;如Web、移动端&#xff09;授权服务…...

NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)

记忆化搜索 在搜索的过程中&#xff0c;如果搜索树中有很多重复的结点&#xff0c;此时可以通过⼀个"备忘录"&#xff0c;记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时&#xff0c;直接在"备忘录"⾥⾯找结果。其中&#xff0c;搜索树中的⼀个⼀个结点…...

ubuntu 服务器版本常见问题

一、系统安装与初始化 1. 安装过程中断或失败 原因:镜像损坏、硬件兼容性、磁盘分区错误。 解决: 验证 ISO 文件的完整性(计算 SHA256 校验和)。 检查 BIOS/UEFI 设置(禁用 Secure Boot)。 使用手动分区模式,确保根分区(/)和 EFI 分区(如有)正确配置。 2. 系…...

【时时三省】(C语言基础)用switch语句实现多分支选择结构 例题

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 例题&#xff1a; 用switch语句处理菜单命令。在许多应用程序中&#xff0c;用菜单对流程进行控制&#xff0c;例如从键盘输入一个 A 或 a 字符&#xff0c;就会执行A操作&#xff0c;输入一…...

全域数字化:从“智慧城市”到“数字生命体”的进化之路

一、国家战略下的城市数字化浪潮 2024年5月&#xff0c;国家四部委联合发布《关于深化智慧城市发展 推进城市全域数字化转型的指导意见》&#xff0c;明确提出以数据为引擎&#xff0c;系统性重塑城市技术架构与管理流程&#xff0c;推动城市治理迈向“全域协同、数实融合”的…...