拼接sql小练习
拼接sql小练习
1.需求
这段代码是我在敲完ydorm(一个简单的orm练习),看到利用反射生成sql后,突然冒出来的想法,就是想把下面的拼接成一个完整的sql
insert into t_student (id,canme,age,Sex) values(?,?,?,?)
[Y001 jack 25 男]
2.代码实现
strsql := "insert into t_student (id,canme,age,Sex) values(?,?,?,?)"
var s1 []interface{}
s1 = []interface{}{"Y001", "jack", 25, "男"}
for i := 0; i < len(s1); i++ {
typ := reflect.TypeOf(s1[i])
fmt.Println(typ)
if typ.Kind() == reflect.String {
strsql = strings.Replace(strsql, "?", s1[i].(string), 1)
}
if typ.Kind() == reflect.Int {
strsql = strings.Replace(strsql, "?", strconv.Itoa(s1[i].(int)), 1) // 问题在这
}
fmt.Println(strsql)
}
3.注意点
3.1 切片转换
拿到的数据是这样的[Y001 jack 25 男]
, 然而在Go中,是不能这样写的!那么我怎么凑这样形式的切片呢,一开始怎么写都不行,于是,我想到了照葫芦画瓢。
我先定义一个整型的切片,看看是什么样子的:
var s2 []int
s2 = []int{1, 2, 3}
fmt.Println(s2)
照葫芦画瓢,定义一个接口类型的切片
var s1 []interface{}
s1 = []interface{}{"Y001", "jack", 25, "男"} // 这里的每一个元素,都是interface类型,这样就可以像py的列表一样可以存放各种数据类型了
3.2 错误理解Replace()方法
我错误理解了这个方法的最后一个参数的含义,最后一个-1代表着全部替换,是代表的是替换个数,而不是替换位置。本以为这个-1代表了最后一个位置,因为Go和python的切片都是这么规定的。于是,我傻傻乎乎的写了-1,还把for循环逆序!最后的结果,显然是错误的!这样写输出的结果是全都替换了成了四个“男”。
3.3 关于.(string)和.(int)
在for循环里的replance语句中,如果不加.(string),Goland直会给出错误提示,这是断言+转换。
s3 := []interface{}{25}
a, ok := s3[0].(int)
fmt.Println(a, ok) // 25,true
fmt.Printf("%T\n", a) // int,可以看到本来是interface{}类型,这里通过(.int)方式直接转换成int类型了
同样的,.(string)也可以将底层为string类型的接口直接转换为string类型,它的两个返回值一个是转换后的值,一个是判断true or false。说明这种写法,不单单可以转换
,还有类似断言
的功能。
在第二节给的源码中,我们使用的是reflect
来判断,下面,我们利用上面的.(string)和(.int)的特性
来实现,代码就更简洁:
strsql := "insert into t_student (id,canme,age,Sex) values(?,?,?,?)"
var s1 []interface{}
s1 = []interface{}{"Y001", "jack", 25, "男"}
for i := 0; i < len(s1); i++ {
if s, ok := s1[i].(string); ok {
strsql = strings.Replace(strsql, "?", s, 1)
}
if s, ok := s1[i].(int); ok {
strsql = strings.Replace(strsql, "?", strconv.Itoa(s), 1) // 问题在这,s是整型,需要转字符串的,所以直接写s是不可以的。
}
fmt.Println(strsql)
}
4.整型和字符型转换
实际编码过程中,还遇到一个困难,就是当遇到25时,程序直接panic掉了。一开始解决思路是仿照string思路,加.(int),加了后发现还是有问题,需要把int转成字符串,Goland也给出了提示,于是,又在前面加了一个string( s1[i].(int)),这次程序没有报错,然而结果是不对的,25那个位置直接是空的!为了验证这个问题,写了下面的测试程序,发现最后输出a的值时,确实是空的,在Go中,无法通过这种方式将整型转成字符串的。
s3 := []interface{}{25}
a, ok := s3[0].(string)
fmt.Println(a, ok)
fmt.Printf("%T\n", a) // int
a1 := string(a)
fmt.Printf("%T %v\n", a1, a1)
正确的转换方式如下:
4.1 int转string
strconv.Itoa(int_number)
该方法的源码是:
// Itoa is shorthand for FormatInt(i, 10).
func Itoa(i int) string {
return FormatInt(int64(i), 10)
}
可以看出是FormatInt方法的简单实现。
4.2 string转int
i, _ := strconv.Atoi("100")
fmt.Println(i)
有了这两个方法,在以后遇到数据类型不兼容时,就可以进行判断后再转换了。
5. 总结
int
和string
类型的互转Replace()
的使用.(string)
和.(int)
类型断言s1 = []interface{}{"Y001", "jack", 25, "男"}
定义这种类型实现类似py中list的功能reflect
使用,一开始没有想到类型断言。直接用reflect
判断了,只要实现了需求,又没有严格的性能要求,当然可以。
果然还是按照自己想法去动手实践,理解的才会更深入一些!