1.Golang中的引用类型
Golang中所有类型在传参的时候都是值传递,但Golang中依然有4种引用类型,分别为slice、map、channel以及interface{}。我们在传递的时候,若要改变参数的值,需要传入该值的指针,对于引用类型则没有这个限制。但在使用的时候也存在一些问题,需要特别注意。
2.当slice元素为interface{}可能出现的问题
func (this *MysqlDB)Find(model interface{}) ([]interface{}, error){
strSql, params, err := GetSelectSql(model, this.Params)
strSql = getSql(strSql, params)
if err != nil{
return nil, err
}
isSuccess, ret := doDB.DB_USE(strSql,"",db.MYSQL_OPT_SELECT,"mysql")
if !isSuccess{
return nil, InsertErr
}
var modelRet []interface{}
for i := 0; i < len(ret.Ret); i++{
//tr := reflect.TypeOf(model).Elem()
//mod := reflect.New(tr).Interface()
temp := model
fmt.Printf("%p",temp)
modelRet = append(modelRet, temp)
}
for j, row := range ret.Ret{
if len(this.fields) == 0{//没有Cols方法,查询所有字段
for i, col := range row{
val := reflect.ValueOf(modelRet[j]).Elem().Field(i+1)
if val.Type() == tableNameType{
continue
}
process(&val, col)
}
} else{//查询指定字段
rt := reflect.TypeOf(modelRet[j]).Elem()
for k, col := range row{
for i := 0; i < rt.NumField(); i++{
if this.fields[k] == strings.ToLower(rt.Field(i).Name){
val := reflect.ValueOf(modelRet[j]).Elem().Field(i)
process(&val, col)
break
}
}
}
}
}
return modelRet, nil
}
在上面的代码中,传入的参数是一个interface类型的变量,传出参数是同类型的slice变量。由于传出参数的长度只有在运行是才知道,所以需要动态的生成一个slice。因此我先根据长度预先生成好slice,代码如下。
var modelRet []interface{}
for i := 0; i < len(ret.Ret); i++{
//tr := reflect.TypeOf(model).Elem()
//mod := reflect.New(tr).Interface()
temp := model
fmt.Printf("%p",temp)
modelRet = append(modelRet, temp)
}
其实最开始的时候,我是直接用model变量向modelRet中添加内容。但是我发现当我后面操作这个slice中的一个元素时,所有的slice元素都跟着一起变。然后我定义了中间变量temp,但当我循环打印temp的地址的时候发现并没有变。也就是说我用append函数向slice元素中添加元素的时候,其实添加的都是同一个元素,且这个元素还是interface{}类型的。这样出现的问题就是,slice中所有的元素都一样,修改一个的时候所有的都一起修改,也就是说append函数并没有拼接,其实底层还是共用同一个元素。那怎么确保slice中所有元素的地址都不一样呢,也就是说,我每次append的时候都需要添加一个新的元素,而不是和之前的一样,这就需要用到反射了。reflect包中有一个reflect.New()函数,可以帮我们解决问题。代码如下:
var modelRet []interface{}
for i := 0; i < len(ret.Ret); i++{
tr := reflect.TypeOf(model).Elem()
mod := reflect.New(tr).Interface()
fmt.Printf("%p",mod)
modelRet = append(modelRet, mod)
}
这样就可以保证我们每次添加进去的都是一个新的元素啦。
3.引用类型怎么拷贝
最重要的就是怎么生成一个新的元素,在2中我们已经实现了,后面只需要利用反射逐个赋值就好了。