类型转换与类型别名
本教程共 93 篇 · 第 11 篇 · 更新于 2026-08-08 · 约 7 分钟阅读
本节目标:读完你能显式地把一种数值类型转换成另一种,并会用 typealias 给类型起一个更贴合场景的别名。
Swift 是类型安全的语言,它有一个”倔脾气”:不同类型的值不会偷偷自动转换。这一章先讲为什么要显式转换、怎么转,再讲类型别名这个小工具。
1-1 为什么不能隐式转换
在有些语言里,Int 和 Double 能直接相加,编译器帮你默默转换。Swift 不这么干。它要求类型的匹配是显式的,目的是把”无意中的错误转换”挡在编译期。
比如一个 Int 和一个 Double 不能直接相加,因为编译器不知道你到底想要整数结果还是小数结果。这种”麻烦”其实是保护:很多隐蔽的精度丢失 bug,都来自悄悄发生的类型转换。
1-2 数值类型怎么转换
转换的写法是”用目标类型当初始化器,把原值包进去”。本质上是调用目标类型的初始化方法。
let three = 3
let pointOneFour = 0.14159
let pi = Double(three) + pointOneFour
// pi 是 Double,值 3.14159
这里 Double(three) 造了一个新的 Double,值是 3。两边都是 Double,相加才合法。注意:字面量 3 和 0.14159 本身没有类型,所以 3 + 0.14159 能直接加——但一旦 3 进了 Int 变量,就必须显式转换。
1-3 整数转浮点、浮点转整数
整数转浮点用 Double(x) 或 Float(x) 即可。反过来,浮点转整数也是显式调用:
let pi = 3.14159
let integerPi = Int(pi) // 3
注意:浮点转整数时,小数部分被直接截断,不是四舍五入。4.75 变成 4,-3.9 变成 -3。这点初学者极易踩坑——想要四舍五入得自己用 rounded() 之类的方法。
let rounded = Int(pi.rounded()) // 3(3.14159 四舍五入仍是 3)
1-4 不同位宽整数间的转换
不同大小的整数类型也不能直接混运算,同样要显式转:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let sum = twoThousand + UInt16(one) // UInt16
UInt16(one) 把 UInt8 的值请进 UInt16,两边类型一致才能相加。每种数值类型能存的范围不同,转换时如果超出目标范围会编译报错——又是一次安全拦截。
1-5 类型别名 typealias
类型别名是给已有类型起一个”外号”。用 typealias 关键字:
typealias AudioSample = UInt16
之后 AudioSample 和 UInt16 完全等价,可以互换使用:
var maxFound = AudioSample.min // 0,等同于 UInt16.min
起别名不改变类型的本质,只是换了个更贴合语境的名字。
1-6 什么时候用类型别名
类型别名最适合”让名字表达业务含义”的场景。比如你处理音频采样,底层是 UInt16,但代码里满屏 UInt16 不如 AudioSample 直观。别的地方也常见:给回调闭包类型起短名、给复杂元组起名等。
typealias CompletionHandler = (Bool) -> Void
这样函数签名里写 CompletionHandler 比写一坨 (Bool) -> Void 清爽。初学阶段用得不多,但看到别人代码里的 typealias 要知道它只是”改了个称呼”。
Tip类型别名是纯语法糖,不改变任何运行时行为。它帮人读代码,不帮机器跑更快。别为了酷而滥用,只在”原名在语境里不够表意”时才加。
1-7 布尔和字符串之间不自动转
再强调一次 Swift 的较真:Bool 和数值之间不会自动互转。你不能把 1 当 true、把 0 当 false 直接用。需要这种映射时,得自己写判断:
let flag = 1
let isOn = (flag == 1) // 显式比较,得到 Bool
显式的好处是意图清楚,别人读代码不用猜”这里 1 到底是不是当真值用”。
1-8 转换与别名的原则
类型转换的”倔脾气”是 Swift 安全哲学的体现。它不帮你悄悄转换,逼你把意图写明确——这能拦下大量隐蔽的精度丢失 bug。记住核心写法:用目标类型当初始化器包住原值,如 Double(three)、Int(pi)。
浮点转整数会被截断而非四舍五入,这是最高频的坑。Int(3.9) 得到 3,Int(-3.2) 得到 -3。想要四舍五入得自己调 rounded() 之类。写财务或需要取整的逻辑时,务必想清楚你要的是”截断”还是”四舍五入”,别想当然。
不同位宽整数之间也不能直接混运算,必须显式转。每种类型能存的范围不同,转换超出目标范围会编译报错——又是一次安全拦截。所以别嫌 UInt16(one) 这种写法啰嗦,它让”我在做什么转换”清清楚楚。
类型别名 typealias 是给已有类型起外号,纯语法糖、零运行时开销。它最适合”让名字表达业务含义”:处理音频采样时 AudioSample 比满屏 UInt16 直观;给回调闭包起短名也比一坨函数签名清爽。但别为了酷滥用,只在”原名在语境里不够表意”时才加。
布尔和数值之间不会自动互转,不能把 1 当 true 用。需要这种映射时自己写判断,显式的好处是意图清楚,别人读代码不用猜。一句话总结转换原则:能不转就不转,要转就显式转,转完想清楚截断还是舍入。类型别名则是”让名字说人话”的小工具。把这两条刻进习惯,涉及数值和类型的代码会稳很多,也更易读。
1-9 补记:对接外部数据
补充一个实际场景:从外部数据(如 JSON、文件)读到的数字,类型往往是具体的 Int64、Double 等,和代码里的 Int 不一定相同,这时显式转换就派上用场。别指望 Swift 替你悄悄转,老老实实写 Int(x) 或 Double(y),既清楚又安全。类型别名在对接这类外部格式时也很实用:比如把 Int64 起个别名 UserId,代码里满屏 UserId 比 Int64 更有业务含义,也方便将来改底层类型。
类型这东西,越显式越安全。Swift 把”隐式转换”这个常见的 bug 源头直接砍掉,短期看多打几个字,长期看少修无数线上故障。接受它的较真,你的代码会更稳。
1-10 小结
Swift 不做隐式类型转换,不同类型相加必须显式包一层目标类型(如 Double(three))。浮点转整数会截断小数而非四舍五入,小心这个坑。类型别名 typealias 给已有类型起更表意的名字,是纯语法糖、零运行时开销。这些规则的核心都是同一件事:让”值的类型”始终清清楚楚,把错误挡在编译期。下一章我们认识元组——把多个值打包在一起的轻量容器。