GoLang学习(三)

本章节主要是Json编码/解码,golang里面的json编码/解码比python还简单,运行环境内置了json函数库,不需要单独安装模块;另外,可以支持自定义struct编解码和Java中的类似,可以把json转换成有类似属性的某个类。有一点需要注意,结构体中如果包含结构体,最好别用指针,否则用起来比较麻烦。

1、非指针方式,以下代码运行和预期一样

//导入模块
import(
        "fmt"
        "encoding/json"
      )
//定义两个数据结构
type Item struct{
    SName string
    IValue int
}
type JObject struct{
    IValue int
    SValue string
    SArray []string
    IArray[] int
    SIMap map[string]int
    OArray []Item
    SOMap map[string]Item
}
//编解码函数
func testEncoding(){
    var obj JObject
        obj.IValue=1
        obj.SValue="this is string"
        obj.IArray=[]int{1,2,3,4,5,5}
        obj.SArray=make([]string,10)
        obj.SIMap=make(map[string]int)
        obj.SIMap["akey"]=1
        obj.SIMap["bkey"]=2
        var item1 Item
            item1.SName="item name"
            item1.IValue=1
        obj.OArray=make([]Item,10)
        obj.OArray[0]=item1
        obj.SOMap=make(map[string]Item)
        obj.SOMap["abc"]=item1
    buf,err :=json.Marshal(&obj)
    if err==nil{
        fmt.Printf("encoding : %s\n",string(buf))
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
func testDecoding(){
    var jsonstring=`{"IValue":1,"SValue":"this is string","SArray":["","","","","","","","","",""],"IArray":[1,2,3,4,5,5],"SIMap":{"akey":1,"bkey":2},"OArray":[{"SName":"item name","IValue":1},null,null,null,null,null,null,null,null,null],"SOMap":{"abc":{"SName":"item name","IValue":1}}}`
    var obj JObject
    err :=json.Unmarshal([]byte(jsonstring),&obj)
    if err==nil{
        fmt.Printf("json decode result : %#v\n",obj)
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
//main函数
func main(){
    testEncoding()
    testDecoding()
}

2、把结构体JObject里面的某个属性修改成指针类型;

type JObject struct{
    IValue int
    SValue string
    SArray []string
    IArray[] int
    SIMap map[string]int
    OArray []*Item   //此处修改成指针数组
    SOMap map[string]Item
}
//编码解码函数需要做相应的调整
func testEncoding(){
    var obj JObject
        obj.IValue=1
        obj.SValue="this is string"
        obj.IArray=[]int{1,2,3,4,5,5}
        obj.SArray=make([]string,10)
        obj.SIMap=make(map[string]int)
        obj.SIMap["akey"]=1
        obj.SIMap["bkey"]=2
        var item1 Item
            item1.SName="item name"
            item1.IValue=1
        obj.OArray=make([]*Item,10)  //此处修改为指针类型
        obj.OArray[0]=&item1  //此处
        obj.SOMap=make(map[string]Item)
        obj.SOMap["abc"]=item1
    buf,err :=json.Marshal(&obj)
    if err==nil{
        fmt.Printf("encoding : %s\n",string(buf))
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
 
//解码函数
func testDecoding(){
    var jsonstring=`{"IValue":1,"SValue":"this is string","SArray":["","","","","","","","","",""],"IArray":[1,2,3,4,5,5],"SIMap":{"akey":1,"bkey":2},"OArray":[{"SName":"item name","IValue":1},null,null,null,null,null,null,null,null,null],"SOMap":{"abc":{"SName":"item name","IValue":1}}}`
    var obj JObject
        obj.OArray=make([]*Item,10) //A:此处初始化一个数组
        var item1 Item
        obj.OArray[0]=&item1 //B:此处引用
    err :=json.Unmarshal([]byte(jsonstring),&obj)
    if err==nil{
        fmt.Printf("item1 : %#v\n",item1)
        fmt.Printf("json decode result : %#v\n",obj)
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}

编码运行结果:通第一个例子
解码运行结果:

item1 : main.Item{SName:"item name", IValue:1}
json decode result : main.JObject{IValue:1, SValue:"this is string", SArray:[]string{"", "", "", "", "", "", "", "", "", ""}, IArray:[]int{1, 2, 3, 4, 5, 5}, SIMap:map[string]int{"akey":1, "bkey":2}, OArray:[]*main.Item{(*main.Item)(0x21021d200), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil)}, SOMap:map[string]main.Item{"abc":main.Item{SName:"item name", IValue:1}}}

数组第一个元素是非空的,因为预先给这个指针引用了一个数据,如果在解码函数中去掉A到B三行,解码出来的数组都会是(nil)。
这就引发一个问题,一般我们不知道数组的长度是多少,也就是A处无法写长度,那么就无法正确解码出来了,得到的都是(nil)。
看decode.go代码的实现,没有对指针的处理,也就是遇到指针的情况没有处理。仔细想是对的,解码函数内部不应该[分配内存]返回一个指针,这个恰恰是调用者应该做的。

所以,如果不用指针用起来会更方便。

————–EOF————–

GoLang学习(二)

项目本身是Java的,用GoLang和Python写项目的测试代码,用前者主要是学习。在三种语言之间切换,错误率明显上升了。:)

同样的功能GoLang比Python代码更简洁一些。下面分析今天出的一个低级错误。

用GoLang模拟一个表单提交,服务器返回的是Json 格式,功能非常简单,代码也不多,没什么好提的。但是在将服务器端返回的字符串转换成自定义结构的时候发现无法赋值。突然一下想起来了, GoLang中需要[导出](也就是可以被其它package访问类似Java中的public)属性或者方法什么的第一个字符要大写,修改了马上OK。

package main
import(
        "fmt"
        "net/http"
        "net/url"
        "io/ioutil"
        "encoding/json"
      )
 
 
type Result struct{
    FailCount int
    SuccessCount int
    FailList []string
    Message string
    Status string
}
 
func testQueryPost(){
    client := &http.Client{}
    form :=make(url.Values)
    form.Add("a","1")
    form.Add("b","1")
    response,err :=client.PostForm("http://localhost:8080/xxxxxx",form)
    buf,err :=ioutil.ReadAll(response.Body)
    //此处略去错误检查。。
    var result Result
    err =json.Unmarshal(buf,&result) 
    if err==nil{
        fmt.Printf(" response body : %#v\n",result)
    }else{
        fmt.Printf(" response Error : %s\n",err.Error())
    }
}
 
func main(){
   testQueryPost()    
}