Go 类型转换与可赋值性
何时可以直接赋值、何时必须显式转换:可赋值性规则、类型转换语法、无类型常量,以及与类型断言的区别。
#type / concept
#status / growing
#tech / dev
#resource / go
[!info] 关联笔记
Go 类型转换与可赋值性
这个概念为什么出现
Go 几乎不做 C/JS 式数值隐式提升:
var a int32 = 1
var b int64 = 2
// c := a + b // 非法
c := int64(a) + b
必须分清:
- 可赋值性:不写转换能否赋值
- 类型转换
T(x):是否允许显式变成T - 类型断言
x.(T):从接口取动态类型(另一专题)
[!abstract] 一句话理解 可赋值性决定“能否直接放入变量/参数”;转换是显式表示变化;断言打开接口看动态类型。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:健康设备把体温从摄氏转到华氏展示
手环上报:
- 整数电量百分比 → 图表库要
float64 - 体温
Celsius→ UI 在部分地区要Fahrenheit - 协议里的无类型常量
1写入byte状态码
三者都碰到“能不能直接赋值,还是必须 T(x)”。
package main
import "fmt"
// Celsius / Fahrenheit 是不同定义类型,单位不同不能默默互赋。
// 业务意图:避免把 °C 数值直接当 °F 显示。
type Celsius float64
type Fahrenheit float64
// toFahrenheit 演示“单位换算必须走显式转换 + 公式”。
// 教学点:Fahrenheit(c) 只是改类型身份,不会自动换算;
// 真正业务换算要自己写公式(这里用简化演示:先转类型再展示原始数)。
func toFahrenheit(c Celsius) Fahrenheit {
// 显式转换:底层都是 float64,允许 T(x)。
// 注意:这不会把 36.5°C 变成 97.7°F;完整公式应是 c*9/5+32。
// 本示例聚焦“转换语法”,换算公式见注释下一行:
// return Fahrenheit(float64(c)*9/5 + 32)
return Fahrenheit(c)
}
func main() {
// 1) 电量:int → float64,必须显式转换。
var batteryPct int = 42
var batteryChart float64 = float64(batteryPct)
// 2) 体温单位类型之间:不同命名类型,直接赋值非法。
var bodyC Celsius = 36.5
// var wrong Fahrenheit = bodyC // 编译错误
bodyF := toFahrenheit(bodyC)
// 3) 无类型常量:在可表示范围内可直接赋给 byte。
const statusOK = 1
var code byte = statusOK
fmt.Println(batteryChart, bodyF, code)
}
建议运行:
go run .
期望输出:
42 36.5 1
结合场景再看三个关注点
-
可赋值 ≠ 可转换
同类型/接口/无类型常量等才能直接赋值;int到float64、Celsius到Fahrenheit要写T(x)。 -
转换不自动表达业务含义
Fahrenheit(c)只换类型标签;真实 °C→°F 还要公式,避免“单位假转换”。 -
无类型常量更宽
const statusOK = 1能进byte;一旦var n int = 1,再赋给byte通常就要显式转换。
核心概念
可赋值性
见 Assignability。常见情形:
- 类型相同
- 接口实现关系满足
nil赋给 pointer/func/slice/map/channel/interface- 无类型常量可表示为目标类型
- 未命名类型与底层类型相同的部分情形
type Celsius float64 与 float64 不同,一般需显式转换。
转换 T(x)
见 Conversions。
int(3.9) // 3
string(65) // "A"
string([]byte{'g', 'o'}) // "go"
数值转换可能截断;字符串与字节切片有专门规则。
无类型常量
常量在定型前更“宽”,使 var x float64 = 1 合法。进入变量后的运算通常要求类型一致。
别名 vs 定义类型
type MyInt = int // 别名,可直接当 int
type ID int // 新类型,需转换
转换 vs 断言
T(x) | x.(T) | |
|---|---|---|
| 对象 | 具体值 | 接口值 |
| 失败 | 多在编译期 | panic / ok=false |
设计动机
显式转换让截断与单位变化可见;无类型常量保留字面量便利。
边界
- 常量
byte(256)非法;变量回绕是另一套规则。 - 接口赋值看方法集。
- 不同
[]T/[]U通常不能直接转换。
常见误区
[!warning] 断言当转换
x.(int)不是int(x)。
[!warning] 期待隐式数值提升
不同整数类型先对齐。
[!warning] 定义类型当别名
type ID int与int不混用。
工程实践
- 领域单位用定义类型防混用
- API 边界集中转换并校验范围
string/[]byte转换成本要测量- 表驱动测试覆盖截断
可验证实验
int32 + int编译否type A int; A(1) + 2const c = 256; var x byte = c- 修改
[]byte是否影响已转换string
本节总结
三线分离:可赋值 / 转换 / 断言。显式是默认。
自测题
- 为何
type A int不能直接赋给int? nil可赋给哪些种类?float64(2)+1里1如何定型?
答案
- 不同已定义类型。
- 指针、函数、slice、map、channel、interface。
- 作为无类型常量在 float64 上下文中变为 float64。
延伸阅读
笔记元信息
- 文件:
go-type-conversion-and-assignability.md - 状态:已深化