Go系列:类型转换

2,423 阅读5分钟

'同'类型转换

对于一个类型T,都有一个对应的类型转换操作T(x)将值x转换为类型T。如果两个类型具有相同的底层类型或二者都是指向相同底层类型变量的未命名指针类型,则二者是可以相互转换。

T(x)

T(x):这种形式的类型转换要求x对象的类型和T是等价类型,即实现了相同的方法。缩减大小的整型转换,以及浮点数与整型的相互转换,可能会改变值或损失精度。

type FT float64  // 定义一个FT类型
f := 273.15
i := FT(273.15)  // 仅仅是改变类型,不改变值得表达方式
f := 1e100   // float64
i := int(f)  // 结果依赖实现 损失精度
f := 3.1415  // float64
i := int(f)  // 3

字符串和[]byte[]rune的转换,Go语言的字符有以下两种类型:

  • byte类型,uint8的别名,代表一个ASCII码字符。
  • rune类型,int32的别名,代表一个UTF-8字符。 字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的,字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成,所以字符串也可以和[]rune类型相互转换。
// 要修改字符串,需要先将其转换成`[]rune或[]byte`,完成后再转换为`string`。
// 无论哪种转换,都会重新分配内存,并复制字节数组。
bs := "hello"         
fmt.Printf("%x\n", &bs)  // 14000096010
bytebs := []byte(bs)  // 强制类型转换为[]byte 类型

bytebs[0] = 'H'       // 修改字符串第一个字符为 H
rbs := string(bytebs)
fmt.Printf("%x\n", &rbs) // 14000096020
fmt.Println(rbs)  // 输出:Hello 强类型转换为 string

rs := "你好"           
runers := []rune(rs)  // 强制类型转换为[]rune 类型
runers[0] = '狗'      // 修改字符串第一个字符为 狗
fmt.Println(string(runers))  // 输出:狗好   强类型转换为 string

x.(T)

类型断言是一个使用在接口值上的操作。语法上它看起来像x.(T)被称为断言类型,这里x表示一个接口的类型,T表示一个类型。

// 成功:第一个返回值为x的动态值,第二个返回值为true
// 失败:第一个返回值为x的类型零值,第二个返回值为false
var w io.Writer = os.Stdout
f, ok := w.(*os.File)      // success:  ok, f == os.Stdout
b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil

跨类型转换

strconv包提供了字符串与简单数据类型之间的类型转换功能。可以将简单类型转换为字符串,也可以将字符串转换为其它简单类型。这个包里提供了很多函数,大概分为几类:

  • 字符串转int:Atoi
  • int转字符串:Itoa
  • ParseT类函数将 string 转换为 T 类型:ParseBool、ParseFloat、ParseInt、ParseUint。由于 string 转其它类型可能会失败,这些函数都有第二个返回值表示是否转换成功
  • FormatT类函数将其它类型转string:FormatBool、FormatFloat、FormatInt、FormatUint
  • AppendT类函数用于将TP转换成字符串后append到一个slice中:AppendBool、AppendFloat、AppendInt、AppendUint 当类型无法转换时该系列函数第二个返回值会报错:
var ErrRange = errors.New("value out of range")  // 例:超过类型上限
var ErrSyntax = errors.New("invalid syntax")     // 例:不是纯数字字符串 转 整型时

int转string

1、fmt.Sprintf函数,使用起来比较方便 int的类型为任意类型,并且该函数还有%b、%d、%o、%x等谓词,添加数字以外的其他信息尤其有用。

x := 123
d := fmt.Sprintf("d=%d", x)  // "123"
fmt.Println(d)

2、strconvItoaFormatT类函数

x := 123
d := strconv.Itoa(x)  // 接收 int 类型参数
fmt.Println(d)        // "123"

// Format类函数:FormatBool()、FormatFloat()、FormatInt()、FormatUint()

// 接收int64类型参数,如是其他int类型需显示转换为int64,第二个参数是进制格式
e := strconv.FormatInt(int64(x), 10) 
fmt.Println(d)            // "123"

var ux uint = 123
u := strconv.FormatUint(uint64(ux), 10)  // 无符号整数 转 string
fmt.Println(u)            // "123"

string转int

string数值类型必须为数字字符串形式;数值范围必须在目标范围内;浮点数无法转整型,否则转换函数的 err != nil 且返回值为0。

1、strconvAtoi函数,由于字符串转换为其它类型可能会失败,所以这些函数都有两个返回值,第一个返回值保存转换后的值,第二个返回值判断是否转换成功。

// Atio函数
// 正整数
s := "123"
i, _ := strconv.Atoi(s)   // string类型数字
fmt.Println(i)            // 123

// 负整数
ms := "-123"
mi, _ := strconv.Atoi(ms)   // string类型数字
fmt.Println(mi)             // -123

2、stringint*ParseT类函数

任何情况下ParseInt的返回值类型都是int64,可以将值转换为较小的类型

s := "123"
// 参数1:数字字符串
// 参数2:转换后值得进制数
// 参数3:返回结果bit的大小,8表示int8、16表示int16、int32、int64,0作为特殊值表示int
i, _ := strconv.ParseInt(s, 10, 32)   // string类型数字 转 10进制 int32
fmt.Println(i)

si, _ := strconv.ParseInt(s, 10,32)
fmt.Printf("si=%d,类型为:%T", si, si) // si=123,类型为:int64
si32 := int32(si)  // 转换为较小类型

3、stringuint*ParseUT类函数

s := "123"
i, _ := strconv.ParseUint(s, 10, 32)   // string类型数字 转 10进制 uint64
si := uint32(i)                        // 转为较小的类型

ms := "-123"
mi, _ := strconv.ParseUint(ms, 10, 32) // 不能转 mi 值为 0

// 还有 ParseBool()、ParseFloat()、ParseInt()、ParseUint()