类型转换
在Golang开发中,类型转换是个不可避免的过程,我们经常需要把字符串转成int、bool类型,使用原生提供的strconv标准包比较繁琐,还需要处理err异常:
func ToInt(a string) int {
b, _ := strconv.Atoi(a)
return b
}
func ToBool(a string) bool {
if a == "true" || a == "TRUE" {
return true
} else if a == "false" || a == "FALSE" {
return false
}
return a == "1"
}
Cast库
介绍
Cast库的作用就是封装了很多类型转换的方法,让引用这个库的开发者,能够以极简的方式把任意类型的值转换成指定类型。
package test
import (
"encoding/json"
"fmt"
"github.com/spf13/cast"
"go-learning/dao"
"testing"
)
func TestCast(t *testing.T) {
str := "123"
fmt.Println(cast.ToString(str)) // 转成string
fmt.Println(cast.ToStringE(str)) // 转成string,有error返回
fmt.Println(cast.ToInt(str)) // 转成int,有error返回
fmt.Println(cast.ToIntE(str)) // 转成int,有error返回
fmt.Println(cast.ToInt64(str)) // 转成int64
fmt.Println(cast.ToInt64(str)) // 转成int64,有error返回
boolStr := "true"
fmt.Println(cast.ToBool(boolStr)) // 转成bool
fmt.Println(cast.ToBoolE(boolStr)) // 转成bool,有error返回
}
原理介绍
其实cast库的原理很简单,以cast.ToString()为例,就是通过断言获取到参数的类型,通过枚举所有支持的类型,结合strconv标准包、类型转换等方式实现任意类型的参数转换成string。
// ToStringE casts an interface to a string type.
func ToStringE(i interface{}) (string, error) {
i = indirectToStringerOrError(i)
switch s := i.(type) {
case string:
return s, nil
case bool:
return strconv.FormatBool(s), nil
case float64:
return strconv.FormatFloat(s, 'f', -1, 64), nil
case float32:
return strconv.FormatFloat(float64(s), 'f', -1, 32), nil
case int:
return strconv.Itoa(s), nil
case int64:
return strconv.FormatInt(s, 10), nil
~~~~
default:
return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i)
}
}
缺点
返回默认值
cast库使用起来是比较简单的,不过也有一些缺点,比如对于不支持的类型,会返回一个默认值,如果使用的是cast.ToString()方法,就无法感知到这个默认值并不是你期望返回的,从而导致程序运行的结果不符合预期。
type MyType int
func TestErrCast(t *testing.T) {
var num MyType = 1
fmt.Println(num) // 1
fmt.Println(cast.ToString(num)) // ""
fmt.Println(cast.ToInt(num)) // 0
fmt.Println(cast.ToInt(int(num))) // 1
}
性能问题
在cast库的原理介绍中,通过ToString()方法介绍了cast库是基于断言、类型转换等方法实现的,在性能上并没有优势,尤其是泛型出现后;
但cast库的优势也很明显,在不追求极致性能的场景下,开发者可以使用简洁的方式实现类型转换,从而让代码看起来更简洁。