2. 常见类型
2.1. 值类型(Value Types)
和其他语言一样,Scala 提供了常见的数值类型。总共有 7 种基本数值类型:
Char
(16 位无符号 Unicode 字符)Byte
(8 位有符号整数)Short
(16 位有符号整数)Int
(32 位有符号整数)Long
(64 位有符号整数)Float
(32 位 IEEE 754 单精度浮点数)Double
(64 位 IEEE 754 双精度浮点数)
除此之外,还有两种值类型:
Boolean
(只能是true
或false
)Unit
(不携带任何信息,常用于表示无返回值)
这些类型在 Java 中都有对应的原始类型。区别在于:Scala 中这些类型是封装类型,任何操作都是函数调用。
接下来我们通过示例来逐一说明。
2.2. Byte
和 Char
Byte
是一个 8 位有符号整数,取值范围为 -128 到 127。而 Char
是 16 位的 Unicode 字符,用于存储人类可读字符。
val b1: Byte = 100
val c1: Char = 'A'
// val b3: Byte = 169 (编译报错)
如果赋值超出 Byte
的范围,编译器会直接报错。如果将 169 赋给 Char
,它会被解释为 ASCII 中的版权符号:
b1 should be(100)
c1 should be('A')
2.3. Int
、Long
和 Short
Int
是 32 位整数,在 Scala 中是数值表示的核心。Long
和 Short
与之类似,只是位宽不同。
val l1: Long = 65536
val i3: Int = 32768
val s1: Short = 32767
// val s2: Short = 32768 (编译报错)
⚠️ 注意:超出 Short
表示范围的值无法直接赋值。
2.4. Boolean
布尔值最简单,只能是 true
或 false
:
val trueVal = true
val falseVal = !true
val falseValOtherWay = !true
trueVal should be (true)
falseVal should be (false)
2.5. Float
和 Double
这两个类型用于表示浮点数,分别对应单精度和双精度:
val f1 = 12.05f // 'f' 表示 Float
val d1 = 12.3495067 // 默认推断为 Double
val d2 = 12.3495067D // 'D' 可选,表示 Double
⚠️ Float
必须以 f
结尾,而 Double
的 D
是可选的。
2.6. 字面量与类型推断
Scala 支持类型推断,无需显式声明类型:
// 类型由赋值内容推断
val i5 = 1234 // Int
val i6 = 0xAFBF // 十六进制,Int
val c5 = 234 // Int
val c6 ='®' // Char
val l4 = 1234L // Long
val l3 = 0xCAFEBABEL // 十六进制 Long
val trueVal = true // Boolean
val falseVal = !true // Boolean
对于 Byte
和 Short
,由于它们是 Int
的子集,必须显式指定类型:
val s2: Short = 32767 // 显式指定 Short
val b1: Byte = 127 // 显式指定 Byte
2.7. String
字符串由双引号包裹,支持转义字符:
val name = "Diego Armando Maradona"
val nameWithQuote = "Kerry O\'keffey"
val ageAsString = "100"
3. 类型之间的转换
3.1. 与 Int
的转换
Scala 支持类型转换,但需遵循规则:
val aByteSizedInteger = 127
val byteFromInt = aByteSizedInteger.toByte
val aNonByteInteger = 128
val wrappedByte = aNonByteInteger.toByte // 溢出回绕
byteFromInt should be (127)
wrappedByte should be (-128)
⚠️ 直接赋值超出范围的值会编译失败,但使用 .toByte()
会自动回绕。
3.2. 从 Char
或 String
转换为 Int
val c4: Char = '®'
val symbolToInt = c4.toInt // Char 转 Int
val stringToInt = "100".toInt
如果字符串包含非数字字符,转换会抛出异常:
val i = "ABC".toInt
// java.lang.NumberFormatException
3.3. Long
的特殊处理
Long
比 Int
范围更大,因此从 Int
转 Long
是安全的,反之则可能丢失精度:
val l = 65536L
val i1 = 65536
val i2 = l // i2 是 Long
// val i2: Int = l ❌ 类型不匹配
val i3 = l.toInt // 显式转换
val s3 = l.toShort
l should be (65536L)
i1 should be (65536)
i2 should equal(i1.toLong)
i3 should equal(i1)
s3 should be (0) // Short 装不下 65536
✅ 建议使用 .toType()
方法显式转换,避免精度丢失。
3.4. 防止错误转换
Scala 提供了验证方法来判断值是否可以转换为目标类型:
val i10 = 127
val i11 = 128
i11.isValidByte should be (false)
i10.isValidByte should be (true)
val i31 = 65536
i31.isValidShort should be (false)
val d3 = 2E31
d3.isValidInt should be (false)
✅ 使用 .isValid{Type}()
可以提前判断值是否在类型范围内。
4. 值类型与引用类型:类型层次结构
Scala 的类型系统有一个清晰的层次结构。除了 String
外,前面提到的基本类型都是值类型,也叫 Value Classes,它们继承自 AnyVal
。
而 String
和我们自定义的类(User-defined Class)则继承自 AnyRef
:
class Article(heading: String, noOfLines: Int)
val i: Int = 1234
val a1: AnyVal = i // Int 转 AnyVal
val article = new Article("Baeldung",2000)
val author = "Eugene"
val parentClass1: AnyRef = article // 自定义类转 AnyRef
val parentClass2: AnyRef = author // String 转 AnyRef
✅ 所有 Scala 类型,最终都是 AnyVal
或 AnyRef
的子类。
5. 是否还有更顶层的类型?
✅ Any
是所有类型的父类(supertype),也叫顶级类型。
它定义了一些通用方法,如 equals()
、hashCode()
和 toString()
。其两个直接子类就是 AnyVal
和 AnyRef
。
6. 总结
本文介绍了 Scala 中常见的数据类型,展示了类型之间的转换规则和类型系统的层次结构。Scala 通过 Any
作为根类型,构建了一个统一的类型体系。
相关代码可在此处查看:GitHub 仓库。