赞
踩
最近项目里面需要查询某一张表,改表某个字段xxx的类型是bit,然后自以为是的使用go的bool来接收该字段值,结果不出意外就出意外了。报错:
sql/driver: couldn't convert "\x01" into type
可见,在底层解析过程中,并不能把mysql的bit类型转化成go的bool。
我们跟踪源码进去底层可以看到,在database/sql/driver/type.go 文件中对目标为bool类型的处理如下
- var Bool boolType
-
- type boolType struct{}
-
- var _ ValueConverter = boolType{}
-
- func (boolType) String() string { return "Bool" }
-
- func (boolType) ConvertValue(src any) (Value, error) {
- switch s := src.(type) {
- case bool:
- return s, nil
- case string:
- b, err := strconv.ParseBool(s)
- if err != nil {
- return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
- }
- return b, nil
- case []byte:
- b, err := strconv.ParseBool(string(s))
- if err != nil {
- return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
- }
- return b, nil
- }
-
- // XXXXXXXX 略
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
目前我们在查询mysql后拿到的src 其实是[]uint8类型(实际上就是 []byte),接着就进入了case []byte 分支,然后这里直接把原数据通过string(s) 强制转换成字符串,导致原来的值 0x01 变成了字符面值为 SOH (通过查看ASCII表)代表标题开始的字符。所以调用strconv.ParseBool 必定失败,因为s根本不符合bool字符量。从而导致错误发生。那么我们要怎么处理这种类型呢?
其实sql包提供了,scan接口:如下
- type Scanner interface {
- // Scan assigns a value from a database driver.
- //
- // The src value will be of one of the following types:
- //
- // int64
- // float64
- // bool
- // []byte
- // string
- // time.Time
- // nil - for NULL values
- //
- // An error should be returned if the value cannot be stored
- // without loss of information.
- //
- // Reference types such as []byte are only valid until the next call to Scan
- // and should not be retained. Their underlying memory is owned by the driver.
- // If retention is necessary, copy their values before the next call to Scan.
- Scan(src any) error
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
只要你的类型实现了该接口,那么就可以操作bit类型了,于是我自定义了类型来接收bit类型。
-
- type MyBool bool
-
- func (b *MyBool) Value() (driver.Value, error) {
- result := make([]uint8, 1)
- if *b {
- result[0] = uint8(1)
- } else {
- result[0] = 0
- }
- return result, nil
- }
- func (b *MyBool) Scan(v interface{}) error {
- bytes := v.([]uint8)
-
- if bytes[0] == 0 {
- *b = false
- } else {
- *b = true
- }
- return nil
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在对应字段上使用该类型,你就可以接受mysql 的bit类型了。(注意这里类型的方法一定是指针对应的方法,否者赋值失败)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。