拼接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. 总结

  • intstring类型的互转
  • Replace()的使用
  • .(string).(int) 类型断言
  • s1 = []interface{}{"Y001", "jack", 25, "男"} 定义这种类型实现类似py中list的功能
  • reflect使用,一开始没有想到类型断言。直接用reflect判断了,只要实现了需求,又没有严格的性能要求,当然可以。
    果然还是按照自己想法去动手实践,理解的才会更深入一些!
posted @ 2022-08-30 16:40  sunnybowen  阅读(34)  评论(0编辑  收藏  举报