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~