简单的案例

一段C++代码案例

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. int a = 5;
  5. float b = 6.2;
  6. a = b; // 这里做了隐式的类型转换
  7. count << a << endl;
  8. }

输出:

  1. 输出:6

但是在go语言中不支持这样的转换。

但是常量到变量之间还是会进行隐式转换的

  1. // b是一个变量 5.0是一个常量
  2. // 这两者之间是支持隐式转换的
  3. var b int = 5.0
  4. // 能够执行成功,且做了转换
  5. fmt.Println(b)
  6. c := 5.0
  7. // 输出 float64
  8. fmt.Printf("%T\n", c)

但是这边也是非常严格的,比如常量:5.1就不能进行赋值

  1. c := 5.0
  2. // 输出 float64
  3. fmt.Printf("%T\n", c)
  4. var d int = c

Cannot use 'c' (type float64) as the type int

变量赋值给另外一个类型的变量,类型不一致,这样是不支持隐式转换的。

简单的转换操作

简单的转换操作

  1. valueOfTypeB= typeB(valueOfTypeA)

在go语言中不支持**变量**间的隐式类型转换

显示类型转换:

  1. c := 5.1
  2. // 输出 float64
  3. fmt.Printf("%T\n", c)
  4. var d int = int(c)
  5. fmt.Println(d) // 5

Cannot convert an expression of the type 'string' to the type 'int'
例如字母格式的string类型abcd就不能转换为int
低精度转换为高精度是安全的,高精度的值转换为低精度的值时会丢失数据,例如int32转换为int16
这种简单的转换方式不能对int(float)string进行互转,要跨大类型转换,可以使用strconv包提供的函数。

strconv

Itoa和Atoi

int转换为字符串:**Itoa()**

  1. fmt.Println("a" + strconv.Itoa(32)) // a32
  1. // Itoa is equivalent to FormatInt(int64(i), 10).
  2. func Itoa(i int) string {
  3. return FormatInt(int64(i), 10)
  4. }

字符串转intAtoi()

  1. // 字符串转 int
  2. fmt.Println(strconv.Atoi("12"))

输出

  1. 12 <nil>

注意它的返回值有2个,一个是int类型,一个是error类型

  1. // 字符串转 int
  2. data, err := strconv.Atoi("12")
  3. if err != nil {
  4. // 转换失败
  5. fmt.Println(err)
  6. }
  7. fmt.Println(data)

Parse类函数

Parse类函数用于转换字符串为给定的类型的值:ParseBool()ParseFloat()ParseInt()ParseUint()

  1. b, _ := strconv.ParseBool("true") // 这里可以写 True 或者 False 可以接收大写开头
  2. fmt.Println(b) // true
  3. b, err := strconv.ParseBool("q")
  4. fmt.Println(err) // strconv.ParseBool: parsing "q": invalid syntax
  5. fmt.Println(b) // false 实际上这里是转换失败的
  1. b, err := strconv.ParseFloat("3.1435", 64)
  2. fmt.Println(err) // <nil>
  3. fmt.Println(b) // 3.1435 且类型为 float64

第二个参数是用来指明转换为:float64还是float32

  1. b, err := strconv.ParseFloat("3.1435", 32)
  2. fmt.Println(err) // <nil>
  3. fmt.Println(b) // 3.1435000896453857
  4. fmt.Printf("%T\n", b) // float64

这里还是转换为float64

  1. func ParseFloat(s string, bitSize int) (float64, error) {
  2. f, n, err := parseFloatPrefix(s, bitSize)
  3. if n != len(s) && (err == nil || err.(*NumError).Err != ErrSyntax) {
  4. return 0, syntaxError(fnParseFloat, s)
  5. }
  6. return f, err
  7. }
  8. func parseFloatPrefix(s string, bitSize int) (float64, int, error) {
  9. if bitSize == 32 {
  10. f, n, err := atof32(s)
  11. return float64(f), n, err
  12. }
  13. return atof64(s)
  14. }

可以看到源码第12行,返回的还是float64,它会不会后面改掉就不知道了。

ParseInt()ParseUint()有3个参数

  1. bitSize参数标识转换为什么位的int/uint,有效值为0,8,16,32,64。当bitSize = 0的时候,标识转换为int或者uint类型,例如bitSize=8表示转换为int8/uint8
  2. base参数标识以什么进制的方式去解析给定的字符串,有效值为:0,2-36。当base = 0的时候,表示根据string的前缀来判断以什么进制去解析:0x开头的以16进制的方式去解析,0开头的以8进制的方式去解析,其他的以10进制的方式解析。
  1. b, err := strconv.ParseInt("3", 10, 0)
  2. fmt.Println(err) // <nil>
  3. fmt.Println(b) // 3
  4. fmt.Printf("%T\n", b) // int64

bitSize = 0的时候会按照下面的方式去获取返回的类型

const intSize = 32 << (^uint(0) >> 63)

  1. func ParseInt(s string, base int, bitSize int) (i int64, err error) {
  2. const fnParseInt = "ParseInt"
  3. if s == "" {
  4. return 0, syntaxError(fnParseInt, s)
  5. }
  6. // Pick off leading sign.
  7. s0 := s
  8. neg := false
  9. if s[0] == '+' {
  10. s = s[1:]
  11. } else if s[0] == '-' {
  12. neg = true
  13. s = s[1:]
  14. }
  15. // Convert unsigned and check range.
  16. var un uint64
  17. un, err = ParseUint(s, base, bitSize)
  18. if err != nil && err.(*NumError).Err != ErrRange {
  19. err.(*NumError).Func = fnParseInt
  20. err.(*NumError).Num = s0
  21. return 0, err
  22. }
  23. if bitSize == 0 {
  24. bitSize = IntSize
  25. }
  26. cutoff := uint64(1 << uint(bitSize-1))
  27. if !neg && un >= cutoff {
  28. return int64(cutoff - 1), rangeError(fnParseInt, s0)
  29. }
  30. if neg && un > cutoff {
  31. return -int64(cutoff), rangeError(fnParseInt, s0)
  32. }
  33. n := int64(un)
  34. if neg {
  35. n = -n
  36. }
  37. return n, nil
  38. }

可以看到bitSize = 0的时候,最终还是会以 int64转换返回

Format类函数

将给定的类型格式化为string类型:FormatBool()FormatFloat()FormatInt()、FormatUint()

  1. s := strconv.FormatBool(true)
  2. fmt.Println(s) // true
  3. fmt.Printf("%T\n", s) // string
  1. s := strconv.FormatFloat(3.1415, 'E', -1,64)
  2. fmt.Println(s) // 3.1415E+00
  3. fmt.Printf("%T\n", s) // string
  1. func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
  2. return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
  3. }

FormatFloat参数众多:

bitSize:表示f的来源类型(float32,float64),会据此进行舍入。

fmt表示格式:

  1. 'b' (-ddddp±ddd, a binary exponent), 指数为二进制
  2. 'e' (-d.dddde±dd, a decimal exponent), 十进制指数
  3. 'E' (-d.ddddE±dd, a decimal exponent), 十进制指数
  4. 'f' (-ddd.dddd, no exponent),
  5. 'g' ('e' for large exponents, 'f' otherwise), 指数很大是用它,否则 f 格式
  6. 'G' ('E' for large exponents, 'f' otherwise), 同上
  7. 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or
  8. 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).

prec控制精度(排除指数部分),对f、e、E,它表示小数点后面的数字个数;对g、G它控制总的数字个数。如果prec为-1,则代表使用最少量的,但又必须的数字来表示f

  1. // 将-42转换为16进制
  2. s := strconv.FormatInt(-42, 16)
  3. fmt.Println(s) // -2a
  4. fmt.Printf("%T\n", s) // string
  1. s := strconv.FormatUint(42, 16)
  2. fmt.Println(s) // 2a
  3. fmt.Printf("%T\n", s) // string