表格5.1显示了Scala的许多基本的类型和其实例值域范围。总体来说,类型Byte,Short,Int,Long和Char被称为整数类型:integral type。整数类型加上Float和Double被称为数类型:numeric type。
表格 5.1 一些基本类型
除了String归于java.lang包之外,其余所有的基本类型都是包scala的成员。 如,Int的全名是scala.Int。然而,由于包scala和java.lang的所有成员都被每个Scala源文件自动引用,你可以在任何地方只用简化名(就是说,像Boolean,或Char,或String这样的名字)。
注意
目前实际上你可以使用与Java的原始类型相一致的Scala值类型的小写化名。比如,Scala程序里你可以用int替代Int。但请记住它们都是一回事:scala.Int。Scala社区实践提出的推荐风格是一直使用大写形式,这也是我们在这本书里做的。为了纪念这个社区推动的选择,将来Scala的版本可能不再支持乃至移除小写变体���因此跟随社区的大流,在你的Scala代码中使用Int而非int才是明智之举。
敏锐的Java开发者会注意到Scala的基本类型与Java的对应类型范围完全一样。这让Scala编译器能直接把Scala的值类型:value type实例,如Int或Double,在它产生的字节码里转译成Java原始类型。
文本
所有在表5.1里列出的基本类型都可以写成文本:literal。文本是直接在代码里写常量值的一种方式。
整数文本
类型Int,Long,Short和Byte的整数文本有三种格式:十进制,十六进制和八进制。整数文本的开头方式说明了数字的基。如果数开始于0x或0X,那它是十六进制(基于16),并且可能包含从0到9,及大写或小写的从A到F的数字。举例如下:
1.scala> val hex = 0x5 2.hex: Int = 5 3.scala> val hex2 = 0x00FF 4.hex2: Int = 255 5.scala> val magic = 0xcafebabe 6.magic: Int = -889275714 请注意,不论你用什么形式的整数文本初始化,Scala的shell始终打印输出基于10的整数值。因此解释器会把你用文本0x00FF初始化的hex2变量的值显示为十进制的255。(当然,你也可以不采信我们的话。开始感受语言的好方法是你一边读本章的时候一边在解释器里试试这些语句。)如果数开始于零,就是八进制(基于8)的,并且只可以包含数字0到7。下面是一些例子:
1.scala> val oct = 035 // (八进制35是���进制29) 2.oct: Int = 29 3.scala> val nov = 0777 4.nov: Int = 511 5.scala> val dec = 0321 6.dec: Int = 209 如果数开始于非零数字,并且没有被修饰过,就是十进制(基于10)的。例如:
1.scala> val dec1 = 31 2.dec1: Int = 31 3.scala> val dec2 = 255 4.dec2: Int = 255 5.scala> val dec3 = 20 6.dec3: Int = 20 如果整数文本结束于L或者l,就是Long类型,否则就是Int类型。一些Long类型的整数文本有:
1.scala> val prog = 0XCAFEBABEL 2.prog: Long = 3405691582 3.scala> val tower = 35L 4.tower: Long = 35 5.scala> val of = 31l 6.of: Long = 31 如果Int类型的文本被赋值给Short或者Byte类型的变量,文本就会被看作是能让文本值在那个类型有效范围内那么长的Short或者Byte类型。如:
1.scala> val little: Short = 367 2.little: Short = 367 3.scala> val littler: Byte = 38 4.littler: Byte = 38 浮点数文本
浮点数文本是由十进制数字,可选的小数点和可选的E或e及指数部分组成的。下面是一些浮点数文本的例子:
1.scala> val big = 1.2345 2.big: Double = 1.2345 3.scala> val bigger = 1.2345e1 4.bigger: Double = 12.345 5.scala> val biggerStill = 123E45 6.biggerStill: Double = 1.23E47 请注意指数部分表示的是乘上以10为底的幂次数。因此,1.2345e1就是1.2345乘以101,等于12.345。如果浮点数文本以F或f结束,就是Float类型的,否则就是Double类型的。可选的,Double浮点数文本也可以D或d结尾。Float文本举例如下:
1.scala> val little = 1.2345F 2.little: Float = 1.2345 3.scala> val littleBigger = 3e5f 4.littleBigger: Float = 300000.0 最后一个值可以用以下(或其他)格式表示为Double类型:
1.scala> val anotherDouble = 3e5 2.anotherDouble: Double = 300000.0 3.scala> val yetAnother = 3e5D 4.yetAnother: Double = 300000.0 字符文本
字符文本可以是在单引号之间的任何Unicode字符,如:
1.scala> val a = 'A' 2.a: Char = A 除了在单引号之间显式地提供字符之外,你还可以提供一个表示字符代码点的前缀反斜杠的八进制或者十六进制数字。八进制数必须在'\'和'\377'之间。例如字母A的Unicode字符代码点是八进制101。因此:
1.scala> val c = '\101' 2.c: Char = A 字符文本同样可以以前缀\u的四位十六进制数字的通用Unicode字符方式给出,如:
1.scala> val d = '\u0041' 2.d: Char = A 3.scala> val f = '\u0044' 4.f: Char = D 实际上,这种unicode字符可以出现在Scala程序的任何地方。例如你可以这样写一个标识符:
1.scala> val B\u0041\u0044 = 1 2.BAD: Int = 1 这个标识符被当作BAD,上面代码里的两个unicode字符扩展之后的结果。通常,这样命名标识符是个坏主意,因为它太难读。然而,这种语法能够允许含非ASCII的Unicode字符的Scala源文件用ASCII来代表。
表格 5.2 特殊字符文本转义序列
最终,还有一些字符文本被表示成特殊的转义序列,参见表格5.2。例如:
1.scala> val backslash = '\\' 2.backslash: Char = \ 字串文本
字串文本由双引号(")环绕的字符组成:
1.scala> val hello = "hello" 2.hello: java.lang.String = hello 引号内的字符语法与字符文本相同,如:
1.scala> val escapes = "\\\"\'" 2.escapes: java.lang.String = \"' 由于这种语法对于包含大量转义序列或跨越若干行的字串很笨拙。因此Scala为原始字串:raw String引入了一种特殊的语法。以同一行里的三个引号(""")开始和结束一条原始字串。内部的原始字串可以包含无论何种任意字符,包括新行,引号和特殊字符,当然同一行的三个引号除外。举例来说,下面的程序使用了原始字串打印输出一条消息:
1.println("""Welcome to Ultamix 3000. 2. Type "HELP" for help.""") 运行这段代码不会产生完全符合所需的东西,而是:
1.Welcome to Ultamix 3000. 2. Type "HELP" for help. 原因是第二行前导的空格被包含在了字串里。为了解决这个常见情况,字串类引入了stripMargin方法。使用的方式是,把管道符号(|)放在每行前面,然后在整个字串上调用stripMargin:
1.println("""|Welcome to Ultamix 3000. 2. |Type "HELP" for help.""".stripMargin) 这样,输出结果就令人满意了:
1.Welcome to Ultamix 3000. 2.Type "HELP" for help. 符号文本
符号文本被写成'< 标识符>,这里< 标识符>可以是任何字母或数字的标识符。这��文本被映射成预定义类scala.Symbol的实例。特别是,文本'cymbal将被编译器扩展为工厂方法调用:Symbol("cymbal")。符号文本典型的应用场景是你在动态类型语言中使用一个标识符。比方说,或许想要定义个更新数据库记录的方法:
1.scala> def updateRecordByName(r: Symbol, value: Any) { 2. // code goes here 3. } 4.updateRecordByName: (Symbol,Any)Unit 方法带了一个符号参数指明记录的字段名和一个字段应该更新进记录的值。在动态类型语言中,你可以通过传入一个未声明的字段标识符给方法调用这个操作,但Scala里这样会编译不过:
1.scala> updateRecordByName(favoriteAlbum, "OK Computer") 2.< console>:6: error: not found: value favoriteAlbum 3. updateRecordByName(favoriteAlbum, "OK Computer") 基本同样简洁的替代方案是,你可以传递一个符号文本:
1.scala> updateRecordByName('favoriteAlbum, "OK Computer") 除了发现它的名字之外,没有太多能对符号做的事情:
1.scala> val s = 'aSymbol 2.s: Symbol = 'aSymbol 3.scala> s.name 4.res20: String = aSymbol 另一件值得注意的事情是符号是被拘禁:interned的。如果你把同一个符号文本写两次,那么两个表达式将指向同一个Symbol对象。
布尔型文本
布���类型有两个文本,true和false:
1.scala> val bool = true 2.bool: Boolean = true 3.scala> val fool = false 4.fool: Boolean = false