Golang使用slice时的问题

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中我们已经实现了,后面只需要利用反射逐个赋值就好了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值