Go xmas2020 学习笔记 12、Structs, Struct tags & JSON
课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主讲老师 Matt Holiday
12-Structs, Struct tags & JSON
Struct
结构通常是不同类型的聚合,所以有不同类型的字段,通过字段查找值。
type Employee struct {
Name string
Number int
Boss *Employee
Hired time.Time
}
func main() {
var e Employee
fmt.Printf("%T %+[1]v", e)
}
main.Employee {Name: Number:0 Boss:<nil> Hired:0001-01-01 00:00:00 +0000 UTC}
通过 \(\%+v\) 显示结构体的字段。通过点表示法插入值。另外的声明方法
var e2 = Employee{
"Matt",
1,
nil,
time.Now(),
}
这种需要按顺序填写所有字段。我们可以指定字段名就可以只写部分
var e2 = Employee{
Name: "Matt",
Number: 1,
Hired: time.Now(),
}
boss := Employee{"Lamine", 2, nil, time.Now()}
e2.Boss = &boss
fmt.Printf("%T %+[1]v\n", e2)
main.Employee {Name:Matt Number:1 Boss:0xc00005e100 Hired:2022-04-08 07:40:49.042803 +0800 CST m=+0.006431301}
由于 \(Boss\) 是指针,在 \(e2\) 的输出中显示的是指针。上方代码也可以写成
boss := &Employee{"Lamine", 2, nil, time.Now()}
e2.Boss = boss
使 \(boss\) 指向结构体指针,在某种意义上创建结构体,匿名获取指针。
使用 \(map\) 管理所有 \(Employee\) 对象
c := map[string]*Employee{}
// c := make(map[string]*Employee)
c["Lamine"] = &Employee{"Lamine", 2, nil, time.Now()}
c["Matt"] = &Employee{
Name: "Matt",
Number: 1,
Boss: c["Lamine"],
Hired: time.Now(),
}
fmt.Printf("%T %+[1]v\n", c["Lamine"])
fmt.Printf("%T %+[1]v\n", c["Matt"])
*main.Employee &{Name:Lamine Number:2 Boss:<nil> Hired:2022-04-08 07:51:11.8676147 +0800 CST m=+0.004987001}
*main.Employee &{Name:Matt Number:1 Boss:0xc00005e040 Hired:2022-04-08 07:51:11.8676147 +0800 CST m=+0.004987001}
Struct Gotcha
c := map[string]Employee{}
c["Lamine"] = Employee{"Lamine", 2, nil, time.Now()}
c["Matt"] = Employee{
Name: "Matt",
Number: 1,
Boss: &c["Lamine"],
Hired: time.Now(),
}
fmt.Printf("%T %+[1]v\n", c["Lamine"])
fmt.Printf("%T %+[1]v\n", c["Matt"])
修改 \(map\) 存储对象,从结构体指针变为结构体,而 \(Employee\) 内的 \(Boss\) 字段需要一个指针,在这种情况下,假设我们从映射中获取对象,并得到其指针,那么 \(IDE\) 会报错。
invalid operation: cannot take address of c["Lamine"]
映射有限制,你不能获取映射内实体的地址。原因在于每当操作地图的时候,如果我将某些内容插入地图或从地图中删除某些内容,地图可以在内部重新排列,因为哈希表数据结构是动态的,那样获得的地址是非常不安全的,可能会变成过时的指针。
c["Lamine"] = Employee{"Lamine", 2, nil, time.Now()}
c["Lamine"].Number++
cannot assign to struct field c["Lamine"].Number in map
如果有一张结构体的映射,对映射中一个该结构体中的值进行修改是不可能的。必须要将结构体的映射修改为结构体指针的映射。
Anonymous Struct Type
func main() {
var album = struct {
title string
artist string
year int
copies int
}{
"The White Album",
"The Beatles",
1968,
1000000000,
}
var pAlbum *struct {
title string
artist string
year int
copies int
}
fmt.Println(album, pAlbum)
}
基于匿名结构类型,并用结构文字初始化,但并不是特别方便。比如创建一个空的匿名结构体指针的时候。
var album1 = struct {
title string
}{
"The White Album",
}
var album2 = struct {
title string
}{
"The Black Album",
}
album1 = album2
fmt.Println(album1, album2)
可以执行这种赋值操作,将拷贝 \(album2\) 的副本复制给 \(album1\) ,两个匿名结构体具有相同的结构和行为(有相同的字段和字段类型)
type album1 struct {
title string
}
type album2 struct {
title string
}
func main() {
var a1 = album1{
"The White Album",
}
var a2 = album2{
"The Black Album",
}
a1 = a2
// a1 = album1(a2)
fmt.Println(a1, a2)
}
而在这种情况下会报错,因为他们不是同一个类型名,但是他们是可以互相转换的。
cannot use a2 (variable of type album2) as album1 value in assignment
判断结构体一致的条件
- 字段一样,字段类型也一样
- 字段按顺序排列
- 相同的字段标签
红圈用于包含一些如何以各种方式进行编码的信息协议。比如为 \(json\) 创建 \(key\),当我们查看 \(json\) 的工作原理时它将使用反射。
但如果它们是一致的,可以进行强制转换。
需要注意的是,从 \(go\ 1.8\) 起,不同字段标签不阻碍类型转换。
Make the zero value useful
\(nil\ [\ ]byte\) 可以使用 \(append\),当 \(buffer\) 被创建时就可以直接被使用,不需要做什么前置工作。
Empty structs
\(struct\{\}\) 在内存中作为单例对象存在,构建空结构体集合比布尔值集合更省空间。
JSON
type Response struct {
Page int `json:"page"`
Words []string `json:"words,omitempty"`
}
func main() {
r := Response{
Page: 1,
Words: []string{"up", "in", "out"},
}
j, _ := json.Marshal(r)
fmt.Println(string(j))
fmt.Printf("%#v\n", r)
var r2 Response
_ = json.Unmarshal(j, &r2)
fmt.Printf("%#v\n", r2)
r3 := Response{
Page: 100,
}
j3, _ := json.Marshal(r3)
fmt.Println(string(j3))
fmt.Printf("%#v\n", r3)
}
\(json.Marshal()\) 返回字节切片,输出到控制台需要转换成 \(string\)。\(json.Unmarshal\) 需要提供一个结构体指针用于存放解析的数据。\(omitempty\) 关键词用于判空,如果为空就省去。否则转换为 \(json\) 的时候会给该字段默认加 \(null\) 值。
字段都以大写开头,这样它们可以被导出。如果字段名以小写开头,\(json\) 不会对它进行编码。
struct field words has json tag but is not exported
从编译器来看程序是正确的,而从 \(linting\ tool\) 静态分析工具来看会给出一个警告。
Go xmas2020 学习笔记 12、Structs, Struct tags & JSON的更多相关文章
- java学习笔记(12) —— Struts2 通过 xml /json 实现简单的业务处理
XML 1.引入dom4j-2.0.0.jar 2.引入jquery-1.8.2.js 3.新建common.js getInfo = function(){ $.post("getXmlA ...
- Ext.Net学习笔记12:Ext.Net GridPanel Filter用法
Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...
- SQL反模式学习笔记12 存储图片或其他多媒体大文件
目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点: 1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...
- golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题
golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...
- Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建
Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...
- Python3+Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)'''from ...
- springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定
springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定 标签: springmvc springmvc学习笔记12-springmvc注解开发之包装类型參数绑定 需求 实现方 ...
- 并发编程学习笔记(12)----Fork/Join框架
1. Fork/Join 的概念 Fork指的是将系统进程分成多个执行分支(线程),Join即是等待,当fork()方法创建了多个线程之后,需要等待这些分支执行完毕之后,才能得到最终的结果,因此joi ...
- matlab学习笔记12单元数组和元胞数组 cell,celldisp,iscell,isa,deal,cellfun,num2cell,size
一起来学matlab-matlab学习笔记12 12_1 单元数组和元胞数组 cell array --cell,celldisp,iscell,isa,deal,cellfun,num2cell,s ...
随机推荐
- java反射获取类的成员函数,成员变量,构造函数
package com.imooc.reflect;import javax.sound.midi.Soundbank;import java.lang.reflect.Constructor;imp ...
- Redis 中的 set 和 sorted set 如何使用,源码实现分析
set 和 sorted set 前言 set 常见命令 set 的使用场景 看下源码实现 insert dict sorted set 常见的命令 使用场景 分析下源码实现 ZADD ZRANGE ...
- kafka 第一次小整理(草稿篇)————分发的基本思路[三]
前言 简单整理一下分发的基本思路. 正文 kafka 原本是做日志管理系统,主要是分发这块的. 那么如何做分发呢? 分发的是什么呢? 分发的其实是日志,日志是事件状态,kafka 内部就叫做Recor ...
- 通过blacklist来禁用驱动
blacklist黑名单 我们在linux中安装驱动,有时会遇到受限或冲突,通常解决方式都是要修改blacklist.conf.对内核模块来说,黑名单是指禁止某个模块装入的机制 在 /etc/modp ...
- 在 Kubernetes 上快速测试 Citus 分布式 PostgreSQL 集群(分布式表,共置,引用表,列存储)
准备工作 这里假设,你已经在 k8s 上部署好了基于 Citus 扩展的分布式 PostgreSQL 集群. 查看 Citus 集群(kubectl get po -n citus),1 个 Coor ...
- C# 将CSV转为Excel
CSV(Comma Separated Values)文件是一种纯文本文件,包含用逗号分隔的数据,常用于将数据从一个应用程序导入或导出到另一个应用程序.通过将CSV文件转为EXCEL,可执行更多关于数 ...
- SpringMVC解决前端传来的中文字符乱码问题
以前乱码问题通过过滤器解决,而SpringMVC给我们提供了一个过滤器,可以在web.xml中添加以下配置 修改了xml文件需要重启服务器! <!--配置解决中文乱码过滤器--> < ...
- BUAA_DS_北航数据结构:输出全排列
输入一个数 \(n\),输出 \(1\sim n\) 的所有全排列,每个排列占一行,每个字符保留 \(5\) 个场宽.勤奋的同学一定已经开始打表了是吧. 说是能做肯定不是骗大家,那怎么做呢~ 其实回溯 ...
- Mybatis配置错误:java.lang.ExceptionInInitializerError
情况一:配置文件,无法被导出或者生效 修改前: 修改后: 究其原因,这是由于Maven的约定大于配置,导致我们写的配置文件,无法被导出或者生效的问题,解决方案: 在pom.xml文件中配置导出非res ...
- python3 爬虫 Scrapy库学习1
1生成项目:生成项目文件夹 scrapy startproject 项目名 2生成爬虫文件 scrapy genspider 爬虫名 指定域名 3进入items文件可以输入自己想要爬取的内容比如 te ...