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(只能是 truefalse
  • Unit(不携带任何信息,常用于表示无返回值)

这些类型在 Java 中都有对应的原始类型。区别在于:Scala 中这些类型是封装类型,任何操作都是函数调用。

接下来我们通过示例来逐一说明。

2.2. ByteChar

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. IntLongShort

Int 是 32 位整数,在 Scala 中是数值表示的核心。LongShort 与之类似,只是位宽不同。

val l1: Long = 65536 
val i3: Int = 32768 
val s1: Short = 32767 
// val s2: Short = 32768 (编译报错)

⚠️ 注意:超出 Short 表示范围的值无法直接赋值。

2.4. Boolean

布尔值最简单,只能是 truefalse

val trueVal = true 
val falseVal = !true 
val falseValOtherWay = !true 

trueVal should be (true) 
falseVal should be (false)

2.5. FloatDouble

这两个类型用于表示浮点数,分别对应单精度和双精度:

val f1 = 12.05f // 'f' 表示 Float
val d1 = 12.3495067 // 默认推断为 Double
val d2 = 12.3495067D // 'D' 可选,表示 Double

⚠️ Float 必须以 f 结尾,而 DoubleD 是可选的。

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

对于 ByteShort,由于它们是 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. 从 CharString 转换为 Int

val c4: Char = '®'
val symbolToInt = c4.toInt // Char 转 Int
val stringToInt = "100".toInt

如果字符串包含非数字字符,转换会抛出异常:

val i = "ABC".toInt
// java.lang.NumberFormatException

3.3. Long 的特殊处理

LongInt 范围更大,因此从 IntLong 是安全的,反之则可能丢失精度:

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 类型,最终都是 AnyValAnyRef 的子类。

5. 是否还有更顶层的类型?

Any 是所有类型的父类(supertype),也叫顶级类型。

它定义了一些通用方法,如 equals()hashCode()toString()。其两个直接子类就是 AnyValAnyRef

6. 总结

本文介绍了 Scala 中常见的数据类型,展示了类型之间的转换规则和类型系统的层次结构。Scala 通过 Any 作为根类型,构建了一个统一的类型体系。

相关代码可在此处查看:GitHub 仓库


原始标题:How to Use Kotlin Range Expressions