在1.18版本中,如何在Unmarshal中应用泛型
积累知识,胜过积蓄金银!毕竟在Golang开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《在1.18版本中,如何在Unmarshal中应用泛型》,就带大家讲解一下知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~
我是 golang 泛型的新手,并进行了以下设置。
- 我收集了大量不同类型的报告。
- 每个报告都有封闭字段
- 所以我将它包装在
reportcontainerimpl中
我使用了 [t reportable] 的类型参数,其中 reportable 定义如下
type reportable interface {
exportdatapointreport | importdatapointreport | missingdatapointreport | sensorthresoldreport
}
类型约束中的每个类型都是要嵌入到容器中的结构。
type reportcontainerimpl[t reportable] struct {
locationid string `json:"lid"`
provider string `json:"pn"`
reporttype reporttype `json:"m"`
body t `json:"body"`
}
当 unmarshal 时,我使用判别器 reporttype 来确定具体类型。
type reporttype string
const (
reporttypeexportdatapointreport reporttype = "exportdatapointreport"
reporttypeimportdatapointreport reporttype = "importdatapointreport"
reporttypemissingdatapointreport reporttype = "missingdatapointreport"
reporttypesensorthresoldreport reporttype = "sensorthresoldreport"
)
由于go不支持struct的类型断言(仅接口),因此在unmarshal时无法转换类型。另外,go 不支持指向“raw”泛型类型的指针。因此,我创建了 reportcontainerimpl 实现的接口。
type reportcontainer interface {
getlocationid() string
getprovider() string
getreporttype() reporttype
getbody() interface{}
}
然后我遇到的问题是,我无法对任何形式或形状的返回类型进行类型约束,并且回到 getbody() 函数上的“自由文本语义” 以允许类型unmarshal 完成时断言。
container, err := unmarshalreportcontainer(data)
if rep, ok := container.getbody().(exportdatapointreport); ok {
// use the reportcontainerimpl[exportdatapointreport] here...
}
也许我理解错了? - 但无论我这样做,我总是会在某个地方需要 interface{} 或在 unmarshal 之前知道确切类型
- 您对如何以类型(更安全)的方式解决此问题有更好的建议吗?
干杯, 马里奥:)
为了完整起见,我在此处添加了 unmarshalreportcontainer
func UnmarshalReportContainer(data []byte) (ReportContainer, error) {
type Temp struct {
LocationID string `json:"lid"`
Provider string `json:"pn"`
ReportType ReportType `json:"m"`
Body *json.RawMessage `json:"body"`
}
var temp Temp
err := json.Unmarshal(data, &temp)
if err != nil {
return nil, err
}
switch temp.ReportType {
case ReportTypeExportDataPointReport:
var report ExportDataPointReport
err := json.Unmarshal(*temp.Body, &report)
return &ReportContainerImpl[ExportDataPointReport]{
LocationID: temp.LocationID,
Provider: temp.Provider,
ReportType: temp.ReportType,
Body: report,
}, err
// ...
}
}
正确答案
但是无论我这样做,我总是会在某个地方需要一个接口{}或在 unmarshal 之前知道确切的类型
正是如此。
实例化某些泛型类型或函数(例如 reportcontainerimpl 或 unmarshalreportcontainer)所需的具体类型必须在编译时(编写代码时)已知。当您使用实际数据填充字节切片时,json 解组会在运行时发生。
要根据某些歧视性值解组动态 json,您仍然需要 switch。
您对如何以类型(更安全)的方式解决此问题有更好的建议吗?
放弃参数多态性。这里不太适合。使用 json.rawmessage 保留现在的代码,在 switch 中有条件地解组动态数据,并返回实现 reportcontainer 接口的具体结构。
作为通用解决方案 - 当且仅当您可以克服这个先有鸡还是先有蛋的问题并在编译时已知类型参数时,您可以编写一个最小的通用解组函数,如下所示:
func unmarshalany[t any](bytes []byte) (*t, error) {
out := new(t)
if err := json.unmarshal(bytes, out); err != nil {
return nil, err
}
return out, nil
}
这只是为了说明原理。请注意, json.unmarshal 已经接受任何类型,因此,如果您的泛型函数实际上除了 new(t) 并返回之外什么都不做,就像在我的示例中一样,它与“内联”整个事物没有什么不同,就好像 unmarshalany 不存在一样.
v, err := unmarshalany[sometype](src)
功能等同于
out := &SomeType{}
err := json.Unmarshal(bytes, out)
如果您计划在 unmarshalany 中放入更多逻辑,则可能需要使用它。你的旅费可能会改变;一般来说,当实际上没有必要时不要使用类型参数。
好了,本文到此结束,带大家了解了《在1.18版本中,如何在Unmarshal中应用泛型》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
使用泛型将接口转变为特定类型的实现方法
- 上一篇
- 使用泛型将接口转变为特定类型的实现方法
- 下一篇
- 使用Golang解析具有嵌套字段的动态JSON数据
-
- Golang · Go问答 | 10分钟前 |
- Go io.Copy 为什么复制后长度不一致
- 393浏览 收藏
-
- Golang · Go问答 | 12分钟前 | URL Go ParseQuery QueryUnescape 加号
- Go URL 为什么加号被解析成空格
- 460浏览 收藏
-
- Golang · Go问答 | 13分钟前 |
- Go http.Request.WriteProxy 为什么代理请求需要完整 URL
- 449浏览 收藏
-
- Golang · Go问答 | 16分钟前 |
- Go ServeMux 为什么路径模式匹配不到
- 480浏览 收藏
-
- Golang · Go问答 | 16分钟前 |
- Go TLS 为什么报 unknown authority
- 103浏览 收藏
-
- Golang · Go问答 | 21分钟前 | 连接池 · 性能排查 · HTTP客户端 · Go问答 · Go 连接复用 MaxIdleConns http.Transport MaxIdleConnsPerHost MaxConnsPerHost
- Go http.Transport 怎样控制单个主机的空闲连接
- 230浏览 收藏
-
- Golang · Go问答 | 27分钟前 | JSON · HTTP客户端 · Go问答 · Go eof http.Client io.ReadAll Response.Body JSON解码
- Go 客户端为什么响应体读不到
- 117浏览 收藏
-
- Golang · Go问答 | 31分钟前 | go · 时间处理 · 故障排查 · Go 时区 time.Parse ParseInLocation
- Go 时间为什么解析带时区字符串失败
- 208浏览 收藏
-
- Golang · Go问答 | 32分钟前 | JSON · go · 排错 · Go encoding/json Decoder JSON未知字段
- Go Decoder 为什么未知字段没有报错
- 394浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 582次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 620次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 654次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 618次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 435次使用
-
- 用Nginx反向代理部署go写的网站。
- 2023-01-17 502浏览
-
- GoLand调式动态执行代码
- 2023-01-13 502浏览
-
- Go JSONJSON null 解码到指针后状态不符合预期怎么办
- 2026-10-18 501浏览
-
- Go crypto/rand.Text 的长度为什么不是固定字符数
- 2026-10-04 501浏览
-
- Go strings.ToValidUTF8 清洗日志内容的边界
- 2026-10-03 501浏览

