golang原生提供了很方便的json处理,例如struct转为json时,直接在成员变量上使用 `json:"name"` 来设置json的字段。通常状况下,对于基础类型 json.Marshal(object) 均可以知足需求,但对于特殊状况就须要经过自定义的json encode解决了。golang
golang官方推荐提供的set方案是经过map来实现的json
custormSet := make(map [CustormStruct] bool) custormObj := custorm.NextObj() if _,ok := custormSet[custormObj];!ok{ custormSet[custormObj] = true }
经过这样方法来实现集合的功能。app
问题是若是一个struct中须要一个set类型的成员变量,并须要转为json。若是直接使用 json.Marshal(object) ,对应类型就会变成一个map,而非咱们须要的元素不重复的list。测试
统计全部访问过本地某个端口的ip,具体数据采集的方法有好几种,不是本文的重点就不介绍了。google
type ListenPort struct{ Port int ipSet map[string] bool ipList []*string } func NewPort(port int) ListenPort{ ipSet := make(map[string] bool) ipList := []*string{} return ListenPort{ port, ipSet, ipList, } } func (p *ListenPort)Add(ip string) { if _,ok:= p.ipSet[ip];!ok{ p.ipSet[ip] = true p.ipList = append(p.ipList,&ip) } } //敲黑板!!!这是重点 func (p ListenPort)MarshalJSON() ([]byte, error){ return json.Marshal(&struct { Port int `json:"port"` Ips []*string `json:"ip"` }{ Port: p.Port, Ips: p.ipList, }) }
ipPort := NewPort(2333) ipPort.Add("127.0.0.1") ipPort.Add("116.211.174.177") ipPort.Add("106.39.167.11") ipPort.Add("220.181.57.2168") ipPort.Add("127.0.0.1") jsonbyte,err := json.Marshal(ipPort) if err != nil { fmt.Println(err) } fmt.Println(string(jsonbyte))
func (obj ObjectType)MarshalJSON() ([]byte, error) 方法应该是实现了json的某个接口。经过从新构造一个struct来解决这个问题。code
代码是我原创的,方法是我google的orm
经过实验能够发现对于reflect对于map,经过如下代码获得的就是一个key list。如下代码打印的结果与打印 p.ipList 同样接口
func (p *ListenPort)PrintlnIpList(){ fmt.Println(reflect.ValueOf(p.ipSet).MapKeys()) }
通过尝试发现,直接使用json转换reflect.Value类型的变量获得的是一个 {}ip
实际上新增了slice储存的是string的地址,并不会增长多少内存。对于reflect.Value类型的确有方法将其再次转换成string类型。只不过每次获取json转换都须要遍历一次slice,这须要本身权衡。内存
ipSet 和ipList为私有成员变量,纯属看业务场景须要
~blablabla~