[Scala基础系列 04]Scala基本类型

1.Scala的数值类型

Scala的数值类型与Java类似,他们的范围与Java也是一致的。与Java不同的是,他们都是对象,是相应的数值类的实例。Scala通过富包装(Rich Wrapper)类给这些数值类型提供了强大的支持。

1.1.数值类型

Scala的数值类型和取值范围,见下表。

  • Boolean: true 或者 false
  • Byte: 8位, 有符号(2-7 ~ 27 - 1)
  • Short: 16位, 有符号 (2-15 ~ 215 - 1)
  • Int: 32位, 有符号 (2-31 ~ 231 - 1)
  • Long: 64位, 有符号 (2-63 ~ 263 - 1)
  • Char: 16位, 无符号 (0 ~ 216 - 1)
  • Float: 32位, 单精度浮点数
  • Double: 64位, 双精度浮点数

你可以像Java中一样使用这些类型。不过,实际上,Scala的类型系统与Java或其他语言,如C#或Java,不太一样,在Scala中,基本类型也是class,比如,Int类型,来自scala.Int,每一个数字,都是scala.Int的一个实例。 统一的类型系统,即原始类型与类的统一,是Scala的一大特点,这一特点让Scala比Java和C#等语言更加面向对象。

请注意
数值类型都被定义为abstract和final的,这意味着,不能通过new获得值类型的实例。创建它们的实例只能通过文本(Literal)

1.2.装箱(Boxing)和拆箱(Unboxing)

熟悉Java或C#等语言的读者会知道,装箱是指将原始类型转换成引用类型(对象),用于需要对象的操作,而拆箱,则是把对象转换成原始类型,用于需要原始类型的场景。

由于数值类型本身已经是类对象,因此Scala里不需要装箱(boxing)和拆箱(unboxing)操作。
当然,Scala代码最终会运行在JVM上,所以实际上,始终会有装箱成Scala类对象,和拆箱成Java原始值类型的操作,但是这些操作是透明的,程序员不需要关心(实际上,这是由定义在Predef中的隐式转换完成的)。

1.3.富包装类(Rich Wrapper)

如上所述,你可以像在Java中一样使用基本类型,不过,Scala实际上提供了非常多的方法给基本类型。这些方法在富包装(Rich Wrapper)里,比如,Int对应的是scala.runtime.RichInt。每一个基本类型都有一个相对应的富包装类。
基本类型,在必要的时候通过隐式转换转换为对应的富包装类,从而可调用富包装类提供的方法。

隐式转换是Scala相当重要的技术,后续文章将会介绍。
下面我们写几行code看一下RichInt的强大功能。

val n1 = 2 max 3
println("2 max 3 = " + n1)

val n2 = -1.abs
println("-1.abs = " + n2)

val n3 = 1 to 5
println("1 to 5 = " + n3)

val n4 = 1.isValidChar
println("1.isValidChar = " + n4)

val n5 = -1.isValidChar
println("-1.isValidChar = " + n5)

2.Scala的字符串(String)

String是非常常用的类型,本质上其实是一系列的Char,但是由于它太常用,在很多方面都有特殊处理,在大多数编程语言里都会被单独列出。

Scala里的String是直接借用了Java的String,也就是说,String只是java.lang.String的一个别名,源代码类似于:

type String = java.lang.String

不过,由于String实际是一系列Char的不可变的集合,Scala中大部分针对集合的操作,都可以用于String,具体来说,String的这些方法存在于类scala.collection.immutable.StringOps中。 由于String在需要时能隐式转换为StringOps,因此不需要任何额外的转换,String就可以使用这些方法。如下所示。

val str = "Hello"
val r1 = str.drop(2)  //"llo"
println("\"Hello\".drop(2) = " + r1)

val r2 = str.dropRight(2) //"Hel"
println("\"Hello\".dropRight(2) = " + r2)

val r3 = str.filter( _ != ‘l‘) //"Heo"
println("\"Hello\".filter( _ != ‘l‘) = " + r3)

val r4 = str.intersect("world")  //"lo"
println("\"Hello\".intersect(\"world\") = " + r4)

与Java或C#一样,String是不可变的,对String进行操作,会得到新的String实例。因此在需要频繁操作String的情况下,请使用StringBuilder。

val builder = new StringBuilder
builder.append("Hello")
builder.append(", world")
builder += ‘!‘
builder.insert(0,"Me: ")
println(builder)   //Me: Hello, world!

3.Scala的类层级

3.1.Scala的统一类型

Scala中,所有的值都是类对象,而所有的类,包括值类型,都最终继承自一个统一的根类型Any。统一类型,是Scala的又一大特点。更特别的是,Scala中还定义了几个底层类(Bottom Class),比如Null和Nothing。类层级结构图如下所示。

3.1.1.顶层类Any

Any是最顶层的类,这意味着,所有的类都是Any的子类型,都可以调用Any类的方法。顶层类Any提供了如下方法,Scala的任意对象都可以调用这些方法。

final def ==(that: Any): Boolean
final def !=(that: Any): Boolean
def equals(that: Any): Boolean
def ##: Int
def hashCode: Int
def toString: String

请注意
以上方法中,== , != 与Java中是有区别的。Scala里,==永远跟equals是一样的,!=则是其否定。==与!=是final的,因此不能被重载。
要比较对象的引用,需使用AnyRef的eq方法。

3.1.2.底层类Null和Nothing

Null是所有引用类型的子类型,而Nothing是所有类型的子类型。Null类只有一个实例对象,null,类似于Java中的null引用。
由于Null是所有引用类型的子类型,这意味着,null可以赋值给任意引用类型,但是不能赋值给值类型。

也许你要问,那么是不是可以将Nothing类的实例对象赋值给值类型。答案是不可以,因为Nothing类没有实例,一个也没有。没有实例的Nothing类有什么作用呢?

Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
这句话不是很好理解,我们用个例子来说明。scala.sys有两个方法error和exit,源代码如下:

def error(message: String): Nothing = throw new RuntimeException(message)

def exit(): Nothing = exit(0)

通过返回类型Nothing,我们就知道,error方法和exit方法不会正常返回。但是我们在调用他们的时候,可以跟所要求的返回值兼容,比如:

def divide(x: Int, y: Int): Int = {
  if (y == 0) error("divide by zero")
  else x / y
}

上面的divide方法要求返回一个Int值,但是如果出错,Nothing也是可以接受的。

另一个用处是在有泛型的地方,由于Scala支持协变(如果不理解协变,没关系),Nothing在必要的时候可以代替其他的类型。 比如List[Nothing]就可以当做任意类型的List[T]使用。恰好,类型List[Nothing],有一个特别的实例,Nil。所以Nil可以当做任意List[T]的实例使用。

3.1.3.Unit类型

在类层级结构图里能看到,在AnyVal的子类型里,有一个特别的类型,Unit。Unit类型用来标识过程,也就是没有明确返回值的函数。 由此可见,Unit类似于Java里的void。Unit只有一个实例,(),这个实例也没有实质的意义。

参考文献:

http://meetfp.com/zh/scala-basic/class-hierarchy

时间: 2024-07-30 03:33:12

[Scala基础系列 04]Scala基本类型的相关文章

[Scala基础系列 10]Scala泛型、类型边界

1.泛型和类型边界 1.1.上限(upper bounds) 我们先看一个简单的实例,用于判断两个变量中较大的值,其中两个变量的类型均为Int型 package com.tv189.advanced /** * Created by molyeo on 2015/8/12. */ class PairInt(val first: Int, val second: Int) { def bigger = { if (first.compareTo(second) > 0) first else s

[Scala基础系列 03]Scala操作符

1.Scala操作符简介 首先,请记住,Scala没有操作符!也没有通常意义上的表达式.你所见到的类似操作符和表达式的语句,其实是方法(函数),它们只是方法的一种比较直观的写法,可以叫做操作符记法. 1.1.二元操作符(中缀表达式) 二元操作符是最常见的操作符,比如,一个简单的表达式1 + 2.其实,“+”是定义在Int类的一个方法,你完全可以用普通方法调用的写法1.+(2).相应的,其他的方法,比如"Hello".drop(2),也可以用操作符记法,"Hello"

[Scala基础系列 05]Scala控制结构

1.If语句 Scala的If语句可以完成其他语言中If语句,于此同时,if/else通常还有值,可以用来赋值,或者代替三元条件运算符(?:).不过它可以比条件运算符更强大,因为你可以在if-else里面写很复杂的程序块. 1.1.普通的If语句 package com.tv189.foundation /** * Created by molyeo on 2015/7/30. */ object IfCondition { def main(args: Array[String]) { val

[Scala基础系列 02]Scala函数

本文主要内容如下: 变量和不变量 函数和过程 函数的参数 分号 1.变量和不变量 1.1.变量 Scala的变量分两种,var和val.var,即variable,类似于我们在Java等其他语言中接触到的变量,而val,是value,类似于我们在其他语言中用到的不可重新赋值的常量,或者final变量. 为什么会有这种区别,这是由于很多情况下,其实你不需要一个可变的var,尤其在函数式编程中,更为明显.不变性能给程序带来很多便利,因此Scala非常强调不可变(immutable)的概念.关于不可变

[Scala基础系列 06]Scala类和对象

1.类和构造函数 Scala中的类,基本概念与其他面向对象语言是一致的,不过在语法上有些不一样的地方.与Java等语言相比,Scala的类语法更简洁,使用起来也更方便. 1.1.类的基本语法 我们先来看一个简单的类定义和使用的代码. class ScoreCalculator { private var total, count = 0 def report(score: Int) { total += score count += 1 } def score = if (count == 0)

[Scala基础系列 07]Scala集合

Scala有一个非常通用,丰富,强大,可组合的集合库:集合是高阶的(high level)并暴露了一大套操作方法.很多集合的处理和转换可以被表达的简洁又可读,但不审慎地用它们的功能也会导致相反的结果.每个Scala程序员应该阅读 集合设计文档:通过它可以很好地洞察集合库,并了解设计动机. 1.数组(Array&ArrayBuffer) 1.1.Array 数组(Array)其实并不在scala.collection包里面,它属于scala包,直接对应于Java的数组,比如,Scala中的Arra

[Scala基础系列 08]Scala继承、抽象类、接口trait以及AOP实现

1.继承 和java一样,scala采用extends关键字继承基类.代码实例如下: /** * Created by molyeo on 2015/8/11. */ class Person(val name: String, var age: Int) { println("The primary constructor of Person") val school = "BJU" def sleep = "8 hours" override

JavaScript基础系列(变量与类型)

以下内容将JavaScript简称为JS 变量指的是,可被修改的数据. 变量这一词在所有的程序语言中都是最为关键.最常见的存在,在JS中也不例外,所以要透彻的了解变量就尤其的重要,必须重视,要想深入变量必须先了解数据类型是什么它在我们实际编码中所起到的作用是什么,接下来一一讲解. (这段话给零基础学习的读者)很多初学者会有疑问,变量到底是干嘛的,可以做些什么啊?举一个最简单的例子:你想通过编写代码实现加减乘除的功能,那么首要的前提就是,你必须要有两个数字,但计算机不认识数字,那么就需要通过计算机

第1节 Scala基础语法:scala中的方法源码分析

val list=List(1,2,3,4) list.reduce((x:Int,y:Int)=>x+y)--->list.reduceLeft((x:Int,y:Int)=>x+y) var first = true var acc:Int = 0 op=(x:Int,y:Int)=>x+y for循环第一次循环:acc=1 first = false第二次循环:acc=op(1,2)=1+2=3第三次循环:acc=op(3,3)=3+3=6第四次循环:acc=op(6,4)=