zoukankan      html  css  js  c++  java
  • golang 类型断言的学习

    在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
    ", 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
    ", 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
    ", 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
    ", decodedRes) //type is map[interface{}]interface{}
    
    	//type assert
    	decodedData, ok := decodedRes.(map[interface{}]interface{})
    	if !ok {
    		fmt.Printf("unexpected type %T
    ", decodedRes)
    	}
    	fmt.Println(decodedData["name"])
    	fmt.Println(decodedData["age"])
    
    	//fmt.Printf("%T
    ", decodedData["friends"]) // type is map[interface{}]interface{}
    	// type assert
    	friendsRes, ok := decodedData["friends"].(map[interface{}]interface{})
    	if !ok {
    		fmt.Printf("unexpected type %T
    ", decodedData["friends"])
    	}
    	for _,v := range friendsRes {
    		//fmt.Printf("type: %T, val: %#v
    ", v,v) // type is map[interface{}]interface{}
    		friend, ok := v.(map[interface{}]interface{})
    		if !ok {
    			fmt.Printf("unexpected type %T
    ", decodedData["friends"])
    		}
    		//fmt.Printf("type: %T, val: %#v
    ", 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/

  • 相关阅读:
    黑马程序员_字符串常用处理方法
    动软代码生成器,主子表增加的时候子表的parentID无法插入问题解决方案
    大数据量高并发的数据库优化详解
    C# Socket网络编程精华篇 (转)
    html+javascript+soap获取webservice免费天气预报信息
    js中字符串怎么转化为日期
    attachEvent方法的作用
    C#中[WebMethod]的用法,aspx、ashx、asmx
    C#操作XML方法详解
    C#操作XML的通用方法总结
  • 原文地址:https://www.cnblogs.com/superfat/p/7376330.html
Copyright © 2011-2022 走看看