本文scala使用的版本是2.11.7
第一章 基础
1.1 基础
常量和变量
以val定义的值是一个常量,即无法改变它的内容:
scala> val counter: Int = 0
counter: Int = 0
以var定义的值是变量,可以改变它的内容:
scala> var v = 0
v: Int = 0
scala> v = 10
v: Int = 10
常用类型
7种数值类型:Byte、Char、Short、Int、Long、Float和Double,以及1个Boolean类型。而且它们的类型都是类。
RichInt、RichDouble、RichChar等,提供了它们堂兄弟——Int、Double、Char等所不具备的便捷方法。
BigInt和BigDecimal类,用于任意大小(但有穷)的数字。这些类分别对应java.math.BigInteger和java.math.BigDecimal。
Scala用底层的java.lang.String类来表示字符串。不过,它通过StringOps类给字符串追加了上百种操作。
操作符重载
a.方法(b)
可以简写为
a 方法 b
例如:
a.+(b)
可以简写为
a + b
函数和方法
不带参数的scala方法通常不使用圆括号。例如:
"Hello".distinct
1.2 习题解答
http://ivaneye.iteye.com/blog/1815550
1. 在Scala REPL中键入3, 然后按Tab键。有哪些方法可以被应用?
这个。。。。直接操作一遍就有结果了.此题不知是翻译的问题,还是原题的问题,在Scala REPL中需要按3. 然后按Tab才会提示。 直接按3加Tab是没有提示的。下面是结果
!= ## % & * +
- / < << <= ==
> >= >> >>> ^ asInstanceOf
equals getClass hashCode isInstanceOf toByte toChar
toDouble toFloat toInt toLong toShort toString
unary_+ unary_- unary_~ |
列出的方法并不全,需要查询全部方法还是需要到Scaladoc中的Int,Double,RichInt,RichDouble等类中去查看。
2. 在Scala REPL中,计算3的平方根,然后再对该值求平方。现在,这个结果与3相差多少?(提示:res变量是你的朋友)
scala> math.sqrt(3)
res18: Double = 1.7320508075688772
scala> 3 - res18 * res18
res19: Double = 4.440892098500626E-16
3. res变量是val还是var?
val是不可变的,而var是可变的,只需要给res变量重新赋值就可以检测res是val还是var了
scala> res19 = 3
<console>:12: error: reassignment to val
res19 = 3
^
4. Scala允许你用数字去乘字符串—去REPL中试一下”crazy”*3。这个操作做什么?在Scaladoc中如何找到这个操作?
scala> "crazy"*3
res20: String = crazycrazycrazy
此方法在StringOps中。
def *(n: Int): String
Return the current string concatenated n times.Definition Classes: StringLike
5. 10 max 2的含义是什么?max方法定义在哪个类中?
scala> 10 max 2
res21: Int = 10
scala> 2 max 10
res22: Int = 10
def max(that: Int): Int
Returns this if this > that or that otherwise.Implicit information: This member is added by an implicit conversion from Int to RichInt performed by method intWrapper in scala.LowPriorityImplicits.
Definition Classes: RichInt → ScalaNumberProxy
6. 用BigInt计算2的1024次方
scala> BigInt(2).pow(1024)
res23: scala.math.BigInt = 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
7. 为了在使用probablePrime(100,Random)获取随机素数时不在probablePrime和Radom之前使用任何限定符,你需要引入什么?
import scala.math.BigInt._
import scala.util.Random
probablePrime(3, Random)
8. 创建随机文件的方式之一是生成一个随机的BigInt,然后将它转换成三十六进制,输出类似”qsnvbevtomcj38o06kul”这样的字符串。查阅Scaladoc,找到在Scala中实现该逻辑的办法。
到BigInt中查找方法。
scala> BigInt(util.Random.nextInt).toString(36)
res26: String = vfhdsd
def toString(radix: Int): String
Returns the String representation in the specified radix of this BigInt.
9. 在Scala中如何获取字符串的首字符和尾字符?
//获取首字符
"Hello"(0)
"Hello".take(1)
//获取尾字符
"Hello".reverse(0)
"Hello".takeRight(1)
10. take,drop,takeRight和dropRight这些字符串函数是做什么用的?和substring相比,他们的优点和缺点都是哪些?
take是从字符串首开始获取字符串;drop是从字符串首开始去除字符串。
takeRight和dropRight是从字符串尾开始操作。
这四个方法都是单方向的。 如果我想要字符串中间的子字符串,那么需要同时调用drop和dropRight,或者使用substring
scala> "Hello".take(2)
res31: String = He
scala> "Hello".drop(3)
res32: String = lo
scala> "Hello".takeRight(3)
res33: String = llo
scala> "Hello".dropRight(2)
res34: String = Hel
scala> "Hello".substring(2,3)
res35: String = l
第二章 控制结构和函数
2.1 控制结构
条件表达式
在Scala中if/else表达式是有值的,即跟在if或else之后的表达式的值。
val v = if (x > 0) "positive" else -1
// 其中一个分支是java.lang.String,而另一个分支是Int。它们的公共超类型叫做Any。
Unit类型,写做(),可以当做Java或C++中的void。
if (x > 1) 1
等价于
if (x > 1) 1 else ()
语句终止
在Scala中,行尾不需要分号。如果单行中写了多个语句,就需要用分号隔开。
块表达式
在Scala中,{}块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
赋值语句的值是Unit类型,所以不要串接赋值。例如下面是不行的:
x = y = 1
输入输出
打印使用print或println函数,而后者会追加一个换行。也可以用printf来格式化字符串。
printf("Hello, %s! You are %d years old.\n", "Fred", 42)
可以用readLine函数从控制台读取一行输入。如果读取数字、Boolean或者字符,可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean或readChar。与其他方法不同,readLine带一个参数作为提示字符串:
val name = readLine("Your name: ")
循环
Scala拥有与Java和C++相同的while和do循环。例如:
while (n > 0) {
r = r * n
n -= 1
}
for语句有些不一样,for (i <- 表达式)
让变量i遍历<-右边的表达式的所有值。
val s = "Hello"
var sum = 0
for (i <- 0 until s.lenght) sum += s(i)
// until方法返回一个不包含上限的区间,如果用to方法,则包含上限。
可以以变量 <- 表达式
的形式提供多个生成器,用分号将它们隔开。
for (i <- 1 to 3; j <- 1 to 3) print((10 * i + j) + " ")
// 结果:11 12 13 21 22 23 31 32 33
每个生成器都可以带一个守卫,以if开头的Boolean表达式:
for (i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")
// 结果:12 13 21 23 31 32
注意在if之前并没有分号
可以在循环中使用变量:
for (i <- 1 to 3; from = 4 - i; j <- from to 3) print((10 * i + j) + " ")
for循环体以yield开始,则该循环会构造一个集合,每次迭代生成集合中的一个值:
scala> for (i <- 1 to 10) yield i % 3
res4: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
这种循环叫做for推导式。
2.2 函数
方法对对象进行操作,函数不是。Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型。但递归函数必须制定返回类型。
默认参数和带名参数
// 默认参数
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
// 带名参数
decorate("Hello", right = ">>>", left = "<<<")
可变长参数列表
def sum(args: Int*) = {
var result = 0
for (arg <- args) result += arg
result
}
通过追加:_*,告诉编译器把参数当做参数序列处理。
def recursiveSum(args: Int*): Int = {
if (args.length == 0)