- 示例工程
- 教程
【免费下载链接】learngo
❤️ 1000+ Hand-Crafted Go Examples, Exercises, and Quizzes. 🚀 Learn Go by fixing 1000+ tiny programs.
Go 是一种静态类型语言,不同类型的值不能直接参与运算或相互赋值,这既是安全性的来源,也是初学者的第一道坎。本文以 learngo 中文版教程 06-变量/05-类型转换/练习/README.md 为骨架,结合仓库内的教学源码与全部 5 个 "Convert and Fix" 练习(含解答),系统讲解类型转换语法、破坏性转换陷阱、转换顺序问题与信息丢失问题。读完本文,你将能独立判断何时需要转换、转换应放在哪一侧,以及如何用int、float64、string等转换表达式修复编译错误并输出正确结果。
一、为什么需要类型转换
在进入练习之前,先看仓库中两个对照示例,它们揭示了类型转换的两条核心规则。
1. 转换可能是"破坏性"操作
01-破坏性的/main.go 展示了最经典的场景:
package main import "fmt" func main() { speed := 100 // int force := 2.5 // float64 // 错误: speed = speed * force // ERROR: invalid op // 转换可以是一个破坏性的操作 // `force` 失去了它的分数部分... speed = speed * int(force) fmt.Println(speed) }如果直接写speed = speed * force,编译器会报invalid operation(无效操作),因为int与float64不能直接相乘。修复方式是先把force转换成int:int(force)会把2.5截断成2,小数部分被丢弃,因此结果不是250而是200。这就是"破坏性转换"的含义——从浮点数转整数时,精度不可避免地损失。
2. 转换的顺序很重要
02-正确的/main.go 展示了同样的算式如何通过"先提升、后截断"保住计算精度:
package main import "fmt" // 转化的顺序很重要... func main() { speed := 100 force := 2.5 fmt.Printf("speed : %T\n", speed) fmt.Printf("conversion: %T\n", float64(speed)) fmt.Printf("expression: %T\n", float64(speed)*force) // 类型不匹配: // speed 是 int // expression 是 float64 // speed = float64(speed) * force // 正确: int * int speed = int(float64(speed) * force) fmt.Println(speed) }这里的关键在于运算过程与赋值目标的类型分离:
float64(speed) * force:先把speed提升为float64,两个float64相乘,结果250.0是精确的;int(...):最后再对完整结果做一次截断,得到250。
对比第一节的写法speed * int(force),虽然两者都能通过编译,但前者在转换前完成了浮点运算、只损失一次精度,后者则提前把2.5截成2,损失了计算精度。先提升、后截断,是浮点与整数混合运算的推荐写法。
二、类型转换语法速览
Go 的转换表达式语法是T(x),其中T是目标类型,x是被转换的值。03-数型转换/main.go 集中展示了数字类型之间、数字到字符串的转换规则:
package main import "fmt" func main() { var apple int var orange int32 // 错误: 不能将 orange 赋值到 apple 上 (不同的类型) // apple = orange // 你需要将 orange 转换为 apple apple = int(orange) // 你不能将一个数字类型转换为布尔类型 // isDelicious := bool(orange) // 但是你可以将 int 转换为 string // 这只对 int 类型生效 orange = 65 // 65 is A color := string(orange) fmt.Println(color) // 这不能运行。65.0 是 float. // fmt.Println(string(65.0)) // 这能运行: 这有两个 byte 值 // byte 也是 int fmt.Println(string([]byte{104, 105})) _ = apple }从这段源码可以提炼出几条可验证的规则:
| 转换 | 是否合法 | 说明 |
|---|---|---|
int(orange)(int32 → int) | 合法 | 同为数字类型,可相互转换 |
bool(orange)(int32 → bool) | 不合法 | 数字不能转换为布尔值 |
string(orange)(int32 → string) | 合法 | 仅对整数类型生效,65对应 ASCII 字符A |
string(65.0)(float → string) | 不合法 | 浮点数不能直接转字符串 |
string([]byte{104, 105}) | 合法 | byte本质是整数,字节切片可转字符串,输出hi |
注意最后一条:byte是uint8的别名,因此字节切片转字符串是合法的,这也是 Go 中将字节序列还原为文本的常见手段。
三、5 个 Convert and Fix 练习详解
这是本文的主体。每个练习都给出"有错误的代码",要求你找到错误并用正确的类型转换修复。建议先自行尝试,再对照解答。
练习 #1:修复int + float64的加法
题目文件:01-convert-and-fix/main.go
package main func main() { // a, b := 10, 5.5 // fmt.Println(a + b) }期望输出:15.5
问题分析:a是int(10),b是float64(5.5),a + b是混合类型运算,编译失败。由于期望输出是15.5(带小数),正确的做法是把int侧提升为float64,而不是把b截断成整数。
解答:01-convert-and-fix/solution/main.go
package main import "fmt" func main() { a, b := 10, 5.5 fmt.Println(float64(a) + b) }要点:当期望结果是浮点数时,应提升整数一侧,即float64(a) + b,得到15.5。
练习 #2:修复跨类型赋值
题目文件:02-convert-and-fix-2/main.go
package main func main() { // a, b := 10, 5.5 // a = b // fmt.Println(a + b) }期望输出:10.5
问题分析:a = b试图把float64赋给int变量,Go 不允许隐式类型转换。同时最后a + b依然是混合类型。修复思路是:把b截断后赋给a(a = int(b),得到10),再把a提升为float64参与加法。
解答:02-convert-and-fix-2/solution/main.go
package main import "fmt" func main() { a, b := 10, 5.5 a = int(b) fmt.Println(float64(a) + b) }运算过程:int(b)把5.5截断为5赋给a;float64(a) + b即10.0 + 5.5 = 15.5……等等,期望输出是10.5?
这里需要重新核对:a初始为10,a = int(b)后a变为5,那么float64(a) + b = 5.0 + 5.5 = 10.5。正确,输出10.5。注意本题的坑点在于a被b覆盖,这是"先转换、再赋值、后使用"的典型流程。
练习 #3:最简单的"修复"
题目文件:03-convert-and-fix-3/main.go,期望输出5.5。
解答:03-convert-and-fix-3/solution/main.go
package main import "fmt" func main() { fmt.Println(5.5) }这一题极简,目的是让你先跑通"改代码 → 编译 → 运行 → 对照期望输出"的完整闭环,为后续较难的题目热身。
练习 #4:常量与变量混合运算
题目文件:04-convert-and-fix-4/main.go,涉及7.5 + age(age为int)。
解答:04-convert-and-fix-4/solution/main.go
package main import "fmt" func main() { age := 2 fmt.Println(7.5 + float64(age)) }要点:7.5是浮点常量,age是int变量,两者不能直接相加;把变量age转换为float64后得到7.5 + 2.0 = 9.5。注意 Go 对无类型常量(如7.5)与有类型变量(如age)的区分——常量的类型由上下文决定,而变量的类型是固定的。
练习 #5:避免转换时的信息丢失
题目文件:05-convert-and-fix-5/main.go
解答:05-convert-and-fix-5/solution/main.go
package main import "fmt" func main() { min := int8(127) max := int16(1000) fmt.Println(max + int16(min)) // 解释 // // `int8(max)` 损失了 max 的信息 // 导致它减小到了 127 // 也就是 int8 的最大值 // // 正确的转换是 int16(min) // 因为 int16 > int8 // 当你这样做时, min 不会损失信息 // // 你会在 "Go 类型系统" 这节学到更多 }这是最有价值的一题,它揭示了转换的信息丢失方向性:
- 错误的做法是
int8(max):max = 1000超出了int8的范围(-128 ~ 127),会被截断为127,信息严重丢失; - 正确的做法是
int16(min):int16能容纳int8的所有取值,min = 127无损升级,1000 + 127 = 1127。
通用原则:向"更宽"的类型转换不会丢信息,向"更窄"的类型转换可能丢信息。当你需要统一两个不同整数类型的运算时,优先把窄类型提升为宽类型。更系统的位宽、溢出与定义类型知识,可继续学习仓库中的 09-go-type-system 章节。
四、配套知识点自测(来自问题集)
与练习配套的 问题/questions.md 收录了 6 道选择题,覆盖了练习之外的重要概念,务必理解每一题:
1. 正确的类型转换表达式是哪个?
convert(40) ✗ var("hi") ✗ int(4.) ✓ ← 正确语法是 类型(值) int[4] ✗Go 的转换表达式是T(x)函数式写法,不是关键字加括号、也不是下标语法。
2.age := 6.5; fmt.Print(int(age))打印什么?
打印6。把 float 转成 int 会丢失小数部分(截断而非四舍五入)。
3.fmt.Print(int(6.5))打印什么?
答案是Compile-Time Error。6.5是无类型常量,常量转换的结果必须是精确的,int(6.5)会丢失精度,因此 Go在编译期就拒绝该表达式。对比上一题:age是float64变量,变量转int允许截断,因此是运行时行为。
4.area := 10.5; fmt.Print(area/2)打印什么?
打印5.25。无类型常量2会自动适配为float64参与除法。
5.area := 10.5; div := 2; fmt.Print(area/div)打印什么?
答案是ERROR。div是int变量,不能除以不同类型的值,与第 4 题形成鲜明对比——常量可自适应,变量必须显式转换。
6. 哪段代码能修复上面的错误?
fmt.Print(int(area)/div) // 5 可用但会截断精度 fmt.Print(area/int(div)) // 类型不匹配,不可用 fmt.Print(int(area)/int(div)) // 5 可用但会截断精度 fmt.Print(area/float64(div)) // ✓ 5.25 正确,先提升再运算正确答案是area/float64(div):把整数变量提升为float64后再除法,既修复了类型不匹配,又保住了10.5 / 2.0 = 5.25的精确结果。前两个可编译选项因先截断area而得到5,属于"能跑但错误"的答案。
五、总结:类型转换的三条铁律
综合教学源码、练习与问题集,可以把 Go 类型转换的核心知识收敛为三条规则:
- 类型不匹配必须显式转换:Go 没有隐式类型转换,
int与float64(乃至int与int32)之间既不能直接运算,也不能相互赋值; - 转换可能是破坏性的:
float64 → int会截断小数部分;向更窄的整数类型转换会溢出截断。因此混合运算推荐"先提升为宽类型、运算完再截断"的顺序(见 02-正确的/main.go); - 常量与变量规则不同:无类型常量可自适应上下文(
area/2合法),而变量必须显式转换(area/div报错);常量转换精度要求更高,int(6.5)直接编译失败。
完成这 5 个练习(练习目录)并吃透配套问题集,你就掌握了 Go 变量章节中最容易出错的一环。后续在 07-printf 格式化输出、08-numbers-and-strings 数字与字符串、以及 09-go-type-system 类型系统中,这些转换知识会被反复用到。
- 示例工程
- 教程
【免费下载链接】learngo
❤️ 1000+ Hand-Crafted Go Examples, Exercises, and Quizzes. 🚀 Learn Go by fixing 1000+ tiny programs.
相关推荐
Learngo Type Conversion 实战:修复 5 个 Convert and Fix 练习,彻底掌握 Go 类型转换
Learngo Type Conversion 实战:修复 5 个 Convert and Fix 练习,彻底掌握 Go 类型转换 导读 本篇文章围绕 06 v
示例工程教程彻底搞懂PyMySQL数据类型映射:避免90%的类型转换坑
彻底搞懂PyMySQL数据类型映射:避免90%的类型转换坑 你是否曾遇到Python整数存入MySQL变成字符串?datetime对象读取后格式异常?本文将系统
数据库数据库客户端后端Winterfell性能优化技巧:打造高性能React表单应用
Winterfell性能优化技巧:打造高性能React表单应用 在现代Web应用开发中,表单是用户交互的核心组件,而React表单库Winterfell凭借其J
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考