数据类型
Scala 的数据类型和Java是类似的,所有Java的基本类型在scala包中都有对应的类,将Scala代码编译为Java字节码时,Scala编译器将尽可能使用Java的基本类型,从而提供基本类型的性能优势
8种基本数据类型,位于scala
包中:
Byte,Short,Int,Long,Float,Double,Char,Boolean
(Java是Integer ,Character )
Scala中没有基本数据类型的概念,所有的类型都是对象
- Any :Any是所有其他类的超类
- AnyRef:Scala里所有引用类(reference class)的基类
-
Unit:只有一个实例值
()
,方法返回Unit 相当于返回了Java中的void - Null:每个引用类的子类
- Nothing:在Scala的类层级的最低端;它是任何其他类型的子类型,可以赋值给任何其他类型,用于异常,表明不正常的返回
def error(message: String): Nothing =
throw new RuntimeException(message)
def divide(x: Int, y: Int): Int =
if (y != 0) x / y
else error("can't divide by zero")
相等比较
Java输出结果为false,因为是两个不同的对象
boolean isEqual(Integer x, Integer y) {
return x == y;
}
System.out.println(isEqual(421, 421));
Scala输出结果为true
scala> def isEqual(x: Any, y: Any) = x == y
isEqual: (x: Any, y: Any)Boolean
scala> isEqual(421, 421)
res1: Boolean = true
scala> def isEqual(x: Int, y: Int) = x == y
isEqual: (x: Int, y: Int)Boolean
scala> isEqual(421, 421)
res2: Boolean = true
Scala中的相等操作==
被设计为对类型的表示是透明的,对于值类型,它是自然的(数字或布尔值)相等
对于Java自动包装的数值类型以外的引用类型,==
等同于从Object
类继承的equals
方法的别名,所以Scala不会出现Java字符串比较的陷阱
scala> val x = new String("abc")
x: String = abc
scala> val y = new String("abc")
y: String = abc
scala> x == y
res1: Boolean = true
scala> x eq y
res2: Boolean = false
scala> x ne y
res3: Boolean = true
eq
和 ne
方法等同于Java的==
比较(引用相等)
创建自己的值类
定义一个值类value class,
它必须只有一个参数,它除了defs之外一定没有任何内容,没有其他类可以扩展值类,并且值类不能重新定义equals
或hashCode
//自定义值类型,而编译的Java字节码将直接使用Int类型
class Dollars(val amount: Int) extends AnyVal {
override def toString() = "$" + amount
}
scala> val money = new Dollars(1000000)
money: Dollars = $1000000
scala> money.amount
res1: Int = 1000000
此外,还可以定义有方法或字段的微类型,有助于理解
class Anchor(val value: String) extends AnyVal
class Style(val value: String) extends AnyVal
class Text(val value: String) extends AnyVal
class Html(val value: String) extends AnyVal
//有助于避免错误,传错位置
def title(text: Text, anchor: Anchor, style: Style): Html =
new Html(
s"<a id='${anchor.value}'>" +
s"<h1 class='${style.value}'>" +
text.value +
"</h1></a>"
)
String 类型
通过双引号包裹起来的字符序列
用三个双引号将字符串包裹起来,原样输出其内容,包括换行符,引号和特殊字符
字符串插值 String Interpolation
从 Scala 2.10.0版本开始,提供了一个新的机制来根据数据生产字符串,通过把变量的引用直接插入到字符串,即字符串插值
val name = "James"
println(s"Hello, $name") // Hello, James
s"Hello, $name" 是待处理的字符串,通过引号之前的字符来标识
用法
一共有三种字符串插值的方式 s
,f
,raw
,字符串插值是通过在编译时重写代码来实现的
s 字符串插值器
在任何字符串前加上s,就可以直接在字符串中使用变量了,也可以处理任意的表达式
对嵌入的表达式进行计算,结果调用toString
替换表达式
单变量的表达式直接放在$符号后边,否则加上大括号
s"The answer is ${6 * 7}."
println(s"1+1=${1+1}")
f插值器
在任何字符串字面前加上 f,就可以生成简单的格式化字符串,功能类似于其他语言的 printf 函数,使用java.util.Formatter类中的格式,百分号开头
val height = 1.9d
val name = "James"
println(f"$name%s is $height%2.2f meters tall") // James is 1.90 meters tall
变量定义后如果没有%
,默认是%s
raw插值器
与 s 插值器在功能上是相同,但是不执行转义字符,使其保持原样
scala> raw"a\nb"
res1: String = a\nb
操作符
操作符实际是方法
val sum = 1 + 2 // Scala invokes 1.+(2)
val longSum = 1 + 2L // Scala invokes 1.+(2L) 方法重载
val s = "Hello, world!"
s indexOf 'o' // Scala invokes s.indexOf('o')
s indexOf ('o', 5) // Scala invokes s.indexOf('o', 5)
任何方法也都可以是操作符,除了中缀运算符(有两个操作数,一个左侧,另一个右侧,例如 +),还有前缀和后缀(unary 一元操作符),前缀运算符只有四个+, -, !, ~
在前缀表示法中,方法名称放在调用方法的对象之前(例如,-7中的' - '),实际函数名称是操作符前加上unary_
,
在后缀表示法中,将方法放在对象之后(例如,7 toLong
中的toLong
),
-2.0 // Scala invokes (2.0).unary_-
操作符优先级
Scala本身没有运算符,只是把方法作为操作符,Scala使用方法的第一个字符来决定优先级。
例如,如果方法名以开头,则它的优先级高于以+开头的方法。 因此2 + 2 * 7
将被计算方式是2 +(2 * 7)
类似地,+++ b *** c
(其中a,b和c是变量,+++和**是方法)将被评估为+++(b *** c)
方法第一个字符的优先级,降序排列
* / %
+ -
:
= !
< >
&
^
|
所有字母
所有赋值操作
例外:以等号字符结束的赋值运算符,如果运算符以等号(=)结尾,并且运算符不是比较运算符<=,>=,==或!=之一,则运算符的优先级与简单赋值(=)相同
同一优先级的多个操作符,通过关联性(associativity)决定操作符的分组方式,关联性通过最后一个字符决定,任何以:
结尾的方法都是右操作数调用,并传入左操作数作为参数,其他字符结尾的方法在左操作数上调用,传入右操作数
无论关联性如何,操作数从左向右计算
a ::: b ::: c // a ::: (b ::: c)
a * b * c// (a * b) * c
操作符字符会被Scala编译器通过添加
$
转化为合法的Java标识符,:->
转化为$colon$minus$greater
,如果要在Java代码中访问标识符,就必须使用这种内部的表示
对象相等性
==
比较,首先确定左侧不是null,然后调用equal
方法进行比较,不同于Java中==
的含义(对于对象,实际比较的是引用的相等性,Scala中有类似的机制 eq
方法)
List(1, 2, 3) == List(1, 2, 3) // true
List(1, 2, 3) == "hello"// false
富类型
基本数据类型都有对应的 富包装(rich wrapper),可以隐式转换为相应的富类型,它具有额外的方法(例如 min max)
基本类型 富类型
Byte scala.runtime.RichByte
Short scala.runtime.RichShort
Int scala.runtime.RichInt
Long scala.runtime.RichLong
Char scala.runtime.RichChar
Float scala.runtime.RichFloat
Double scala.runtime.RichDouble
Boolean scala.runtime.RichBoolean
String scala.collection.immutable.StringOp
控制结构
最大的特点是if, for, try, match和函数调用都会产生一个返回值
break和continue不再使用
if
var filename = "default.txt"
if (!args.isEmpty)
filename = args(0)
// 通过直接获取返回值,把变量类型设为 val
val filename =
if (!args.isEmpty) args(0)
else "default.txt"
while 循环
while循环返回值为Unit
,表明有一个返回值,称为 unit value,写作()
while循环通过和var
类型一同出现,不推荐使用
var line = ""
while ((line = readLine()) != "") // 错位的写法
println("Read: " + line)
Scala 中赋值语句的返回值是
Unit
,同String类型比较,永远为true(不同于C,Java等语言)
for循环
枚举集合
数组,集合,Range类型均可
for( x <- Range ){
statement(x);
}
<-
叫做生成器(generator),实际生成scala.collection.immutable.Range.Inclusive
集合
Range 可以是i to j
或者i until j
i to j
生成的集合范围[i,j]
i until j
生成的范围是[i,j)
Range 设定步长
设定每次增加的长度
def to(end: Int, step: Int): Inclusive // 1 to (5, 2)
def until(end: Int, step: Int): collection.immutable.Range // 1 until (5, 2)
嵌套循环
通过分号分隔,将会遍历到每一种可能的组合
for( a <- 1 to 3; b <- 1 to 3){
println( "Value of a: " + a );
println( "Value of b: " + b );
}
def grep(pattern: String) =
for {
file <- filesHere
if file.getName.endsWith(".scala")
line <- fileLines(file)
trimmed = line.trim //中间可以绑定运算结果到新的变量
if trimmed.matches(pattern)
} println(file + ": " + trimmed)
grep(".*gcd.*")
过滤
只有满足if条件的才能输出,可以添加多个条件,用分号分隔
for( x <- List
if condition1;
if condition2...
){
statement(s);
}
产生新的集合
使用 for-yield 语法for (enumerators) yield e
,for循环每次执行的结果会添加到集合中,返回的集合类型取决于enumerators中的集合类型
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
yield (i, j)
foo(10, 10) foreach {
case (i, j) =>
print(s"($i, $j) ") // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5)
}
try表达式
在Scala中throw
表达式有返回值,类型是Nothing
val half =
if (n % 2 == 0)
n / 2
else
throw new RuntimeException("n must be even")
import java.io.FileReader
val file = new FileReader("input.txt")
try {
// Use the file
} finally {
file.close() // Be sure to close the file
}
try-catch-finally
也有返回值,
如果没有引发异常,则返回try子句
如果抛出并捕获异常,则返回相关catch语句
如果抛出异常但未捕获,表达式根本没有结果
在finally子句中计算的值(如果有的话)会被删除
import java.net.URL
import java.net.MalformedURLException
def urlFor(path: String) =
try {
new URL(path)
} catch {
case e: MalformedURLException =>
new URL("http://www.scala-lang.org")
}
match表达式
匹配表达式类似其他语言中的switch表达式,从多种选择中进行选择
区别如下:
- case类型没有限定(Java中只有整形,枚举和字符串常量)
- 每个选项语句结尾没有
break
,会隐含一个break
- match表达式可以返回一个值
val firstArg = if (args.length > 0) args(0) else ""
val friend =
firstArg match {
case "salt" => "pepper"
case "chips" => "salsa"
case "eggs" => "bacon"
case _ => "huh?"
}
println(friend)
变量作用域
Scala中可以在内部作用域中定义一个与外部作用域中的变量具有相同名称的变量
内部变量屏蔽了同名的外部变量,因为外部变量在内部范围内变得不可见
val a = 1;
{
val a = 2
println(a) //2
}
println(a) //1
网友评论