复制成功
请遵守本站 许可
REPORT
Chapter_Post // Field_Report

Post_Ref: RL-CH07-TPC

2026.05.03

Ch.07:Go的类型转换

Chongxi
Chongxi
Listening: IDLE_SESSION
#教程#Golang
ANALYSIS

TL;DR:本文介绍了在Golang中类型转换

Go 有一条规则你必须得记:不同类型之间不能直接运算或赋值,必须显式转换。 没有隐式转换,没有自动提升,一切都要明确写出来

为什么没有隐式转换#

很多语言会自动转换类型,比如 C 里 intfloat 可以直接运算,语言帮你悄悄处理。Go 不打算这样干

原因很简单:隐式转换会掩盖 bug。你以为两个数字在相加,实际上发生了精度丢失或者溢出,但没有任何提示。Go 让一切都显式发生,出了问题一眼看出来

PRTCL // GO
var a int = 10
var b float64 = 3.14
fmt.Println(a + b) // 报错:mismatched types int and float64

必须手动转换:

PRTCL // GO
fmt.Println(float64(a) + b) // 10 + 3.14 = 13.14

数字类型之间的转换#

语法是 目标类型 ( 值 )

PRTCL // GO
var a int = 42
var b float64 = float64(a) // int → float64
var c int = int(b) // float64 → int

简单吧,但有几个细节要注意

浮点转整数:直接截断,不四舍五入

PRTCL // GO
var f float64 = 3.99
var n int = int(f)
fmt.Println(n) // 3,不是 4

小数部分直接丢掉,不管是 3.1 还是 3.9,结果都是 3。需要四舍五入要用 math.Round()

PRTCL // GO
import "math"
f := 3.99
n := int(math.Round(f))
fmt.Println(n) // 4

大类型转小类型可能会溢出

PRTCL // GO
var a int32 = 1000
var b int8 = int8(a)
fmt.Println(b) // -24,溢出了

int8 最大 127,1000 放不下,发生溢出。Go 不报错,静默地给你错误的结果,这是最危险的情况,你要自己保证转换前值在目标类型的范围内

有符号和无符号互转同样可能出问题

PRTCL // GO
var a int = -1
var b uint = uint(a)
fmt.Println(b) // 18446744073709551615,-1 变成了极大的正数

负数转无符号整数,结果完全不符合预期

整数和浮点互转的精度损失

PRTCL // GO
var a int64 = 9999999999999999
var b float64 = float64(a)
var c int64 = int64(b)
fmt.Println(a == c) // false,精度丢失了

float64 的有效精度约 15-16 位,超大整数转浮点再转回来,可能和原始值不一样

字符串和 []byte、[]rune 互转#

上一篇讲过,这里整理一下:

PRTCL // GO
s := "Hello, 世界"
// string → []byte
bs := []byte(s)
// []byte → string
s2 := string(bs)
// string → []rune
rs := []rune(s)
// []rune → string
s3 := string(rs)

单个数字转字符串,不要用 string()

PRTCL // GO
n := 65
fmt.Println(string(n)) // "A",不是 "65"

string(65) 把 65 当作 Unicode 码点,返回对应的字符 "A",不是数字 65 的字符串形式。要得到 "65"strconv.Itoa()

strconv 包:字符串和数字互转#

字符串和数字之间不能用类型转换语法,要用 strconv

PRTCL // GO
import "strconv"

整数和字符串#

整数转字符串,Itoa

PRTCL // GO
n := 42
s := strconv.Itoa(n)
fmt.Println(s) // "42"
fmt.Printf("%T\n", s) // string

字符串转整数,Atoi

PRTCL // GO
s := "42"
n, err := strconv.Atoi(s)
if err != nil {
fmt.Println("转换失败:", err)
} else {
fmt.Println(n) // 42
}

Atoi 返回两个值:结果和错误。字符串不一定是合法的整数,所以必须处理错误:

PRTCL // GO
s := "abc"
n, err := strconv.Atoi(s)
if err != nil {
fmt.Println(err) // strconv.Atoi: parsing "abc": invalid syntax
}
fmt.Println(n) // 0,转换失败时结果是零值

浮点数和字符串#

浮点数转字符串,FormatFloat

PRTCL // GO
f := 3.14159
// 'f' 格式(普通小数),2 位小数,float64
s := strconv.FormatFloat(f, 'f', 2, 64)
fmt.Println(s) // "3.14"
// 'e' 格式(科学计数法)
s2 := strconv.FormatFloat(f, 'e', 4, 64)
fmt.Println(s2) // "3.1416e+00"
// 'g' 格式(自动选择最短表示)
s3 := strconv.FormatFloat(f, 'g', -1, 64)
fmt.Println(s3) // "3.14159"

参数说明:第一个是值,第二个是格式(f/e/g),第三个是精度(-1 表示最短表示),第四个是位数(32 或 64)

字符串转浮点数,ParseFloat

PRTCL // GO
s := "3.14"
f, err := strconv.ParseFloat(s, 64) // 64 表示 float64
if err != nil {
fmt.Println("转换失败:", err)
} else {
fmt.Println(f) // 3.14
}

布尔值和字符串#

布尔转字符串:

PRTCL // GO
b := true
s := strconv.FormatBool(b)
fmt.Println(s) // "true"

字符串转布尔:

PRTCL // GO
s := "true"
b, err := strconv.ParseBool(s)
if err != nil {
fmt.Println("转换失败:", err)
} else {
fmt.Println(b) // true
}

ParseBool 能识别 "1""t""true""TRUE" 为 true,"0""f""false""FALSE" 为 false,其他值报错

ParseInt 和 ParseUint 的通杀解析#

Atoi 只能解析十进制整数,ParseInt 更灵活:

PRTCL // GO
// 解析十六进制
n, err := strconv.ParseInt("ff", 16, 64) // 基数 16,位数 64
fmt.Println(n) // 255
// 解析二进制
n2, err := strconv.ParseInt("1010", 2, 64)
fmt.Println(n2) // 10
// 基数 0:根据前缀自动判断(0x 十六进制,0b 二进制,0o 八进制)
n3, err := strconv.ParseInt("0xff", 0, 64)
fmt.Println(n3) // 255

整数转指定进制的字符串:

PRTCL // GO
n := 255
fmt.Println(strconv.FormatInt(int64(n), 2)) // "11111111",二进制
fmt.Println(strconv.FormatInt(int64(n), 16)) // "ff",十六进制
fmt.Println(strconv.FormatInt(int64(n), 10)) // "255",十进制

fmt.Sprintf 的格式化转换#

除了 strconv,还可以用 fmt.Sprintf 把任意值转成字符串:

PRTCL // GO
n := 42
f := 3.14
b := true
s1 := fmt.Sprintf("%d", n) // "42"
s2 := fmt.Sprintf("%.1f", f) // "3.1"
s3 := fmt.Sprintf("%v", b) // "true"
s4 := fmt.Sprintf("%v", n) // "42",%v 是通用格式

%v 是万能格式,任何类型都能用,但不如专用格式精确。Sprintfstrconv 灵活,但速度稍慢,需要高性能场合用 strconv

接口类型的转换#

接口类型是 Go 里一个特殊的存在,它可以存任意类型的值。从接口类型取回具体类型,需要用类型断言

现在不需要完全理解接口,只需要知道类型断言的语法,后面接口那篇会深入讲

PRTCL // GO
var i interface{} = "hello"
// 类型断言
s, ok := i.(string)
if ok {
fmt.Println(s) // "hello"
} else {
fmt.Println("不是 string")
}

i.(string) 断言 i 里存的是 string,返回两个值:实际值和是否成功

不带 ok 的写法,断言失败会直接 panic:

PRTCL // GO
s := i.(string) // 如果 i 不是 string,程序崩溃

ok 的写法更安全,断言失败 okfalses 是零值,程序不崩溃

自定义类型之间的转换#

上一篇提到可以用 type 定义新类型:

PRTCL // GO
type Celsius float64 // 摄氏度
type Fahrenheit float64 // 华氏度

虽然两者底层都是 float64,但它们定义上是不同的类型,不能直接运算:

PRTCL // GO
var c Celsius = 100
var f Fahrenheit = Fahrenheit(c) // 必须显式转换

底层类型相同的自定义类型之间可以互转:

PRTCL // GO
type Celsius float64
type MyFloat float64
var c Celsius = 100
var m MyFloat = MyFloat(c) // 底层都是 float64,可以转

但自定义类型和内置类型之间也需要显式转换:

PRTCL // GO
type MyInt int
var a MyInt = 10
var b int = int(a) // MyInt → int
var c MyInt = MyInt(b) // int → MyInt

转换性能考量#

大多数类型转换在编译阶段处理,运行时没有额外开销。但有几种转换会分配内存,需要注意:

string[]byte 互转会复制数据:

PRTCL // GO
s := "hello"
bs := []byte(s) // 复制了一份数据

频繁转换在高性能场合是个负担。Go 1.20 之后可以用 unsafe 包做零拷贝转换,但那是进阶话题,现在不用管

fmt.Sprintfstrconv 慢:

做大量数字转字符串,用 strconv.Itoa,不要用 fmt.Sprintf("%d", n)。差距在基准测试里明显,日常少量转换无所谓

常见坑#

string( 整数 ) 不是数字转字符串

PRTCL // GO
fmt.Println(string(65)) // "A",不是 "65"
fmt.Println(strconv.Itoa(65)) // "65",这才对嘛

浮点转整数不四舍五入

PRTCL // GO
int(3.9) // 3,不是 4

需要四舍五入用 math.Round()

大转小溢出不报错

PRTCL // GO
int8(1000) // -24,静默溢出

转换前自己确认值在目标范围内

负数转无符号整数

PRTCL // GO
uint(-1) // 18446744073709551615

有符号负数转无符号,结果完全不符合预期

Atoi 错误没处理

PRTCL // GO
n, _ := strconv.Atoi("abc")
fmt.Println(n) // 0,这里他悄悄失败了

转换失败时结果是零值,如果直接用这个零值继续运算,bug 很难追踪。你要养成错误必须要处理的习惯


下一篇讲运算符,算术、比较、逻辑、位运算,以及 Go 里一些和其他语言不同的地方

R P
Rhine Lab Pioneer Division
Auth_Verified: 2026.05.03
// END OF POST
Donation_Channel // Support_Us

如果觉得本文不错,不妨请我喝杯咖啡。

爱发电
golearn
Series_Associated // 专题收录

从0带你学Golang

该文章已被收录至本站深度研究专题。点击进入项目主页,查看完整研究序列。

Classified
Chapter_06 // Legal_Protocol
Protocol_Ref: CC-BY-NC-SA-4.0

Ch.07:Go的类型转换

Author: CHONGXI // Released: 2026.05.03

本受试报告采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 许可协议进行分发。

} } out>