在php中有一個 serialize() 函數 可以把數組序列化成字元串進行存儲和傳輸 如果想反序列化這種字元串,在php中只需要一個簡單的unserialize() 函數就可以完成了.但是在golang中可就沒有這麼容易了,非得費個九牛二虎之力,寫上不少代碼才行。 這時候只想感嘆一下,php真的是 ...
在php中有一個 serialize() 函數 可以把數組序列化成字元串進行存儲和傳輸
如果想反序列化這種字元串,在php中只需要一個簡單的unserialize() 函數就可以完成了.但是在golang中可就沒有這麼容易了,非得費個九牛二虎之力,寫上不少代碼才行。
這時候只想感嘆一下,php真的是世界上最好的語言啊!
我就在今天的開發中遇到了這麼個問題,需要使用golang去解析php序列化的字元串,在github上找了個解析的包,但是發現解析之後的結果是個interface{}類型。
頓時我就無從下手了,總在想數據實際上是一個map,但是解析後得到一個interface{} , 這讓我怎麼用啊
感覺需要用類型斷言,但又不太會用,遂去社區問一下吧,期望大佬們能給個答案。
實際上確實很管用。
下麵貼一下代碼:
package main import ( "github.com/yvasiyarov/php_session_decoder/php_serialize" "fmt" "log" ) func main() { // 序列化後的字元串 str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}` // 反序列化 decoder := php_serialize.NewUnSerializer(str) if result, err := decoder.Decode(); err != nil { panic(err) } else { // 此處進行類型斷言 decodeData, ok := result.(php_serialize.PhpArray) if !ok { log.Println(err) } // 斷言後,即可獲取內容 name := decodeData["name"] age := decodeData["age"] fmt.Println(name, age) // 內層數據仍需再次斷言 friends, ok := decodeData["friends"].(php_serialize.PhpArray) if !ok { log.Println(err) } // 斷言成功後即可獲取內部數據 for _,v := range friends { fmt.Printf("type:%T, value:%+v\n", v,v ) friend, ok := v.(php_serialize.PhpArray) if !ok { log.Println(err) } friendName := friend["name"] fmt.Println(friendName) } } }
可以粗暴的這麼理解:一個變數是什麼類型,就進行什麼類型的斷言,斷言後,即可得到結果
怎麼判斷一個變數的類型?
列印出來呀:fmt.Printf("%T", verb)
%T這個占位符可以顯示變數的類型
下麵還有個示例:
package main import ( "github.com/yvasiyarov/php_session_decoder/php_serialize" "fmt" "log" ) func main() { // 序列化後的字元串 str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}` // 反序列化 decoder := php_serialize.NewUnSerializer(str) result, err := decoder.Decode() if err != nil { panic(err) } // 類型斷言 t := result.(php_serialize.PhpArray) strVal := php_serialize.PhpValueString(t["name"]) fmt.Println(strVal) switch t := result.(type) { default: fmt.Printf("unexpected type %T\n", t) case php_serialize.PhpArray: fmt.Println(t) fmt.Println(t["name"]) fmt.Println(t["age"]) switch f := t["friends"].(type) { default: fmt.Printf("unexpected type %T\n", t) case php_serialize.PhpArray: fmt.Println(f) fmt.Println(f[0]) fmt.Println(f[1]) } } }
上面兩個demo都可以達到效果,只是寫法不同。
後面我又經人介紹,得到了另外一個包,也能達到效果:
package main import ( "fmt" "log" "github.com/wulijun/go-php-serialize/phpserialize" ) func main() { str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}` decodedRes, err := phpserialize.Decode(str) if err != nil { panic(err) } //fmt.Printf("%T\n", decodedRes) //type is map[interface{}]interface{} //type assert decodedData, ok := decodedRes.(map[interface{}]interface{}) if !ok { fmt.Printf("unexpected type %T\n", decodedRes) } fmt.Println(decodedData["name"]) fmt.Println(decodedData["age"]) //fmt.Printf("%T\n", decodedData["friends"]) // type is map[interface{}]interface{} // type assert friendsRes, ok := decodedData["friends"].(map[interface{}]interface{}) if !ok { fmt.Printf("unexpected type %T\n", decodedData["friends"]) } for _,v := range friendsRes { //fmt.Printf("type: %T, val: %#v\n", v,v) // type is map[interface{}]interface{} friend, ok := v.(map[interface{}]interface{}) if !ok { fmt.Printf("unexpected type %T\n", decodedData["friends"]) } //fmt.Printf("type: %T, val: %#v\n", friend,friend) // type is map[interface{}]interface{} fmt.Println(friend["name"]) } }
這個包解析出來的所有結果的類型都是map[interface{}]interface{},所以做類型斷言的時候可以簡單粗暴一些
下麵是我在segmentfault和stackoverflow上面的提問,我上面的示例demo也是來源於問題中大佬們的回答,有興趣可以看下:
segmentfault:https://segmentfault.com/q/1010000010690732
stackoverflow:https://stackoverflow.com/questions/45705930/how-to-get-values-from-a-interface-in-golang/