当前位置: 首页 > 编程日记 > 正文

Scala Learn 1 Basic

Chap 0 前言

focus on:

  1. Scala 的语法十分简洁

  2. Scala 运行在虚拟机之上, 可以使用 java 的海量类库和工具

  3. Scala 拥抱函数式编程的同时,并没有废弃面向对象

  4. Scala 既有动态语言那样的灵活简洁,同时有保留了静态类型检查的安全与执行效率

  5. Scala 既能处理脚本化的临时任务,又能处理高并发场景下的分布式互联网大数据应用,可谓能缩能伸

Chap 1 基础

focus on:

  1. 使用 scala 解释器

  2. 用 var 和 val 定义变量

  3. 数字类型

  4. 使用操作符和函数

  5. 浏览 Scaladoc

1.1 Scala解释器

scala> 8 * 5 + 2
res1: Int = 42scala> 0.5 * res1
res4: Double = 21.0scala> "Hello, " + res1
res5: String = Hello, 42
{ String = java.lang.String }

scala 程序并不是一个解释器。
输入的内容被快速地编译成字节码,然后这段字节码交由 Java 虚拟机执行。
我们称之为 : REPL

scala> res5.to  // tab 补全
toByte   toChar   toDouble   toFloat   toInt   toLong   toShort   toStringscala> res5.toUpperCase
res6: String = HELLO, 42

1.2 声明值和变量

Scala 鼓励使用 val, 除非你真的需要改变它。声明值和变量不初始化会报错。

注: 你不需要给出值和变量的类型,scala会根据初始化的值推断出来。

scala> val answer = 8 * 5 + 2
answer: Int = 42scala> answer * 0.5
res8: Double = 21.0

在必要的时候,你也可是指定类型

scala> val greeting: String = null
greeting: String = null
scala> val greeting: Any = "Hello"
greeting: Any = Helloscala> val xmax, ymax = 100
xmax: Int = 100
ymax: Int = 100

1.3 常用类型

Byte、Char、Short、Int、Long、Float、Double。和 Boolean。

与 Java 不同的是,这些类型是 类。

scala> 1.toString()
res9: String = 1scala> 1.to(10)
res10: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Scala不需要包装类型。在基本类型和包装类型之间转换是 Scala 编译器的工作。

Scala 用 java.lang.String 类来表示字符串。不过,它通过 StringOps 类给字符串追加了上百种操作。

举例 intersect : scala> "Hello".intersect("World")
res11: String = lo

在这个表达式中,java.lang.String 对象 "Hello" 被隐式地转换成一个 StringOps 对象,接着 StringOps 类的 intersect 方法被应用。

同样 Scala 还提供了 RichInt、RichDouble、RichChar 等 to 方法就是 RichInt 类中的方法。

还有 BigInt 和 BigDecimal类,用于任意大小(但有穷)的数字。这些类背后是 java.math.BigInteger 和 java.math.Bigdecimal,在scala中,他们用起来更方便,可以用常规操作符来操作它们。

scala> val x: BigInt = 1234567890
x: BigInt = 1234567890scala> x * x * x
res13: scala.math.BigInt = 1881676371789154860897069000

1.4 算术/操作符重载

    + - * / % 位 & | ^ >> << 都是完成通常的工作。只是有一点特别,这些操作符实际上是方法。  a + b 其实是  a.+(b)      + 是方法名。

Scala 并不会傻乎乎的 对方法名中使用非字母或数字 这种做法 带有偏见

如 BigInt 类就定义了一个名为 /% 的方法,该方法返回一个对偶 (商、余数)
1.to(10) 也可以写成 1 to 10.

Scala 没有提供 ++, -- 这种操作符。

1.5 调用函数和方法

除了方法之外,scala 还提供函数。相比 Java,在 Scala 中使用数学函数 (比如 : min 或 pow) 更为简单 ---- 你不需要从某个类调用它的静态方法

scala> import scala.math._ 或 import math._ 说明: _ 通配符类似java *
import scala.math._scala> sqrt(2) 或者 math.sqrt(2)
res15: Double = 1.4142135623730951scala> pow(2, 4)
res16: Double = 16.0scala> min(3, Pi)
res17: Double = 3.0

Scala 没有静态方法,

Scala有一个特性,叫做单例对象(singleton object)

通常一个类对应有一个 伴生对象 (companion object),其方法就跟 Java 中的静态方法一样。举例来说,BigInt 类的 BigInt 伴生对象有一个生成指定位数的随机素数的方法 probablePrime:

scala> BigInt.probablePrime(100, scala.util.Random)
res33: scala.math.BigInt = 882882747840768533709728498879

说明 : 这里的 Random 是一个单例随机数生成器对象,而该对象是在 scala.util 包中定义的。这里用单例对象比用类更好的为数不多的场景之一。在Java中,为每个随机数都构造出一个新的java.util.Random对象是一个常见的错误。

Scala 没有参数且不改变当前对象的方法不带圆括号。如 :

scala> "Hello".distinct
res34: String = Helo

1.6 apply 方法

在 Scala 中,我们通常都会使用类似函数调用的语法。

scala> "Hello"(4)
res35: Char = o相当于 C++ s[i], Java 的 s.charAt(i)举例来说 在 StringOps 类的文档中,你会发现这样一个方法def apple(n: Int): Char"Hello"(4) 相当于 "Hello".apply(4)

如果去看 BigInt 伴生对象的文档,就会看到让你将字符串或数字转换为 BigInt 对象的 apply 方法。

scala> BigInt("12345")
res36: scala.math.BigInt = 12345scala> BigInt.apply("12345")
res37: scala.math.BigInt = 12345这个语句产生一个新的 BigInt 对象,不需要使用 new。
使用伴生对象apply方法是 Scala中 构建对象的常用手法scala> Array(1, 4, 9, 16)
res38: Array[Int] = Array(1, 4, 9, 16)scala> Array.apply(1, 4, 9, 16)
res39: Array[Int] = Array(1, 4, 9, 16)

1.7 Scaladoc

Java 程序员使用 Javadoc 浏览 Java API。

Scaladoc www.scala-lang.org/api 在线浏览 Scaladoc

www.scala-lang.org/download#api

注意每个类名旁边的 O 和 C,它们分别链接到对应的类 (C) 或 伴生对象 (O).

  • 如果你想使用数值类型,记得看看 RichInt、RichDouble等。字符串看StringOps

  • 数学函数 scala.math 包中

  • BigInt 有一个方法叫做 unary_-. 这就是你定义前置的负操作符 -x 的方式

  • 标记为 implicit 的方法对应的是自动(隐式)转换。比如: BigInt 对象拥有在需要时自动被调用的由 int 和 long 转换为 BigInt 的方法。

  • 方法可以以函数作为参数。 如 def count(p: (Char) => Boolean) : Int
    调用类似方法时,你通常可以一种非常紧凑的表示法给出函数定义。

scala> var s = "HelLo"
s: String = HelLoscala> s.count(_.isUpper)
res42: Int = 2
  • 最后,当你偶尔遇到类似 StringOps 类中这样的看上去几乎没法一下子理解的方法签名时. 例如下情况 :

    def patch [B >: Char, That](from: Int, patch: GenSeq[B], replaced: Int) (implicit bf: CanBuildFrom[String, B, That]): That
  • 别紧张,直接忽略即可,还有另一个版本的 patch, 看上去容易讲得通

    def patch(from: Int, that: GenSeq[Char], replace: Int): StringOps[A]
  • 如果你把 GenSeq[Char] 和 StringOps[A] 都当做 String 的话,这个方法从文档理解起来就简单多了。当然,在 REPL 中试用也很容易:

    scala> "Harry".patch(1, "ung", 2)
    res43: String = Hungry

Chap 2 控制结构和函数

focus on:

  1. Scala 中,几乎所有的构造出来语法结构都有值。(区别于Java语句没有值)

  2. if、块、 表达式 有值

  3. void 类型是 Unit

  4. 避免在函数定义中使用 return

  5. 注意别在函数式定义中漏掉了=。

  6. Scala 没有受检异常

2.1 条件表达式

scala> var x = -4
x: Int = -4scala> val s = if (x > 0) 1 else -1
s: Int = -1scala> if (x > 0) "positive" else -1
res0: Any = -1
{说明 : 类型不同,返回值为公共超类型 Any}scala> if (x > 0) 1
res1: AnyVal = ()scala> if (x > 0) 1 else ()
res2: AnyVal = ()
{说明 :  这两条语句相同。()=Unit, (java void)}

2.2 块表达式-赋值

scala> val k = {val dx = 2; val dy = 3; math.sqrt(dx * dx + dy * dy)}
k: Double = 3.605551275463989scala> x = y = 1
<console>:9: error: type mismatch;found   : Unitrequired: Intx = y = 1^
{注意 : 赋值语句的值是 Unit}

2.3 输入和输出

scala> print("Answer: ")
Answer:
scala> print(42)
42
scala> println("Answer : " + 42)
Answer : 42scala> // C风格 的 printf
scala> printf("Hello, %s! You are %d years old. \n", "fern", 28)
Hello, fern! You are 28 years old.

从控制台读取 readLine, readInt, readDouble ...

scala> val name = readLine("Your name : ")
warning: there was one deprecation warning; re-run with -deprecation for details
Your name : name: String = Beanscala> val age = readInt()
warning: there was one deprecation warning; re-run with -deprecation for details
age: Int = 25readDouble、readByte、readShort、readLong、
readFloat、readBoolean、readChar。

2.4 循环

scala> var n = 3
n: Int = 3
scala> var r = 1
r: Int = 1scala> :paste
// Entering paste mode (ctrl-D to finish)
while (n > 0) {r = r * nn -= 1
}
// Exiting paste mode, now interpreting.scala> print(n)
0
scala> print(r)
6
scala> var n = 3
n: Int = 3scala> 1 to n
res13: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3)scala> for (i <- 1 to n) {|   r = r*i| }
scala> print(r)
36

说明 :

  • RichInt 类 这个 to 方法,返回 Range(区间)

  • 在 for 循环的变量之前并没有 val 或 var 的指定。该变量的类型是集合的原色类型。循环变量的作用域一直持续到循环结束。

scala> val s = "Hello"
s: String = Helloscala> var sum = 0
sum: Int = 0scala> for (i <- 0 until s.length)| sum += s(i)scala> sum
res7: Int = 500scala> var sum = 0
sum: Int = 0你可以直接遍历字符序列,不需要使用下标scala> for (ch <- "Hello") sum += chscala> sum
res9: Int = 500

说明 : Scala 并没有直接提供 break 或 continue 语句来退出循环。

2.5 for循环、for推导式

可以以 变量 <- 表达式 的形式提供多个生成器,用分号将它们隔开。

scala> for (i <- 1 to 3; j <- 1 to 3) print ((10*i + j) + " ")
11 12 13 21 22 23 31 32 33

生成器可以带着守卫条件

scala> for (i <- 1 to 3; j <- 1 to 3 if i != j) print ((10*i + j) + " ")
12 13 21 23 31 32

注意 : if 之前没有 分号

===

你可以使用任意多的定义,引入可以在循环中使用的变量 :

scala> for (i <- 1 to 3; from = 4 - i; j <- from to 3) print ((10*i + j) + " ")
13 22 23 31 32 33

循环体以 yield 开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值

scala> for (i <- 1 to 10) yield i % 3
res12: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)

这叫做 for推导式。 for推导式 生成的集合 与 它的第一个生成器是类型兼容的

scala> for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar
res16: String = HIeflmlmopscala> for (i <- 0 to 1; c <- "Hello") yield (c + i).toChar
res17: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p)scala> 0 to 3
res20: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3)

2.7 函数

定义函数,给出: 名称、参数、函数体

scala> def abs(x: Double) = if (x >= 0) x else -x
abs: (x: Double)Doublescala> abs(-5)
res22: Double = 5.0scala> def fac(n: Int) = {| var r = 1| for (i <- 1 to n) r = r * i| r| }
fac: (n: Int)Intscala> fac(3)
res23: Int = 6

我们最好适应没有 return 的日子,很快你就可以使用大量匿名函数。return 相当于 函数版的 break。

对于递归函数,必须指定返回类型,Scala 不是 Haskell, Scala 猜测不出来

scala> def fact(n: Int): Int = if (n <= 0) 1 else n * fact(n-1)
fact: (n: Int)Intscala> fact(4)
res24: Int = 24

2.8 默认参数和带名参数

scala> def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
decorate: (str: String, left: String, right: String)Stringscala> decorate("Hello")
res26: String = [Hello]scala> decorate(left = "<<<", str = "Hello", right = ">>>")
res29: String = <<<Hello>>>

2.9 变长参数

scala> def sum(args : Int*) = {|   var result = 0|   for (arg <- args) result += arg|   result| }
sum: (args: Int*)Intscala> val s = sum(1, 4, 9, 16, 25)
s: Int = 55

值的序列 调用是错误的。 告诉编译器 当做 参数序列 处理

scala> val s = sum(1 to 5)
<console>:8: error: type mismatch;found   : scala.collection.immutable.Range.Inclusiverequired: Intval s = sum(1 to 5)^scala> val s = sum(1 to 5: _*)
s: Int = 15

递归这样解决

scala> def resurSum(args: Int*): Int = {|   if (args.length == 0) 0|   else args.head + resurSum(args.tail: _*)| }
resurSum: (args: Int*)Intscala> resurSum(1, 2, 3, 4, 5)
res31: Int = 15

因为 序列的 head 是它的首个元素,tail 是 其他元素的序列。

2.10 过程

不返回值函数的特殊表示法。 不建议使用

2.11 懒值

当 val 被声明为 lazy 时,它的初始化将被推迟,直到我们首次对它取值。

lazy val words = scala.io.Source.fromFile("~/words").mkString

懒值对于开销较大的初始化语句而言十分有用。

可以把 懒值 当做是介于 val 和 def 的中间状态。

说明 : 懒值并不是没有额外开销。我们每次访问懒值,都会有一个方法被调用,而这个方法将会以线程安全的方式检查该值是否已被初始化。

2.12 异常

Scala 的异常工作机制 和 Java / C++ 类似。

如 :

throw new IllegalArgumentException("x should not be negative")

当前运算被中止,运行时系统查找可接受 IllegalArgumentException 的异常处理器

和 Java 一样,抛出的对象必须是 java.lang.Throwable 的子类。不过,与 Java 不同的是,Scala 没有 “受检” 异常 -- 你不需要声明说函数或方法可能会抛出某种异常。

throw 表达式有特殊的类型 Nothing。 这在 if/else 表达式中有用。如果一个分支的类型是 Nothing,那么 if/else 表达式的类型就是另一个分支的类型。举例来说, 考虑如下代码

scala> var x = -1
x: Int = -1scala> if (x >= 0) {|   math.sqrt(x)| } else throw new IllegalArgumentException("x should not be negative")
java.lang.IllegalArgumentException: x should not be negative... 37 elided

第一个分支类型是 Double,第二个分支类型是 Nothing。 因此,if/else 表达式的类型是 Double。

捕获异常的语法采用的是模式匹配的语法。

scala> try {|   process(new URL("http://horstmann.com/fred-tiny.gif"))| } catch {|   case _: MalformedURLException => println("Bad URL: " + url)|   case ex: IOException => ex.printStackTrace()| }

和 Java 一样,更通用的异常应该排在更具体的异常之后。

注意,如果你需要使用捕获的异常对象,可以使用 _ 来替代变量名

try / finally 语句让你可以释放资源。

try { ... } finally { ... }

try { ... } catch { ... } finally { ... }

Chap 3 数组操作

focus on:

  1. 若 长度固定 则使用 Array, 若长度可能有变化则使用 ArrayBuffer。

  2. 提供初始值时不要使用 new

  3. 用 () 来访问元素

  4. 用 for (elem <- arr) 来遍历元素

  5. 用 for (elem <- arr if ...)...yield... 原数组转型为新数组

  6. Scala数组 和 Java数组 可以互操作; 用 ArrayBuffer, 使用 scala.collection.JavaConversions 中的转换函数

3.1 定长数组

scala> val nums = new Array[Int](10)
nums: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)scala> val a = new Array[String](10)
a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)

已经提供初始值就不需要 new.

scala> val s = Array("Hello", "World")
s: Array[String] = Array(Hello, World)scala> s(0) = "Goodbye"scala> s
res7: Array[String] = Array(Goodbye, World)
scala> Array(2,3,5,7)
res8: Array[Int] = Array(2, 3, 5, 7)

Array(2,3,5,7) 在 JVM 中是 int[]

3.2 变长数组

Java ArrayList -- C++ vector -- Scala ArrayBuffer

scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBufferscala> val b = ArrayBuffer[Int]()
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()scala> b += 1
res9: b.type = ArrayBuffer(1)scala> b += (1, 2, 3, 5)
res11: b.type = ArrayBuffer(1, 1, 2, 3, 5)scala> b ++= Array(8, 13, 21)
res12: b.type = ArrayBuffer(1, 1, 2, 3, 5, 8, 13, 21)scala> b.trimEnd(5)scala> b
res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2)

在数组的尾端添加 或 删除元素是一个高效的操作。

在任意位置插入或移除元素是低效。(之后的元素都需要平移)

scala> b.insert(2, 6)scala> b
res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 6, 2)scala> b.insert(2, 7, 8, 9)scala> b.remove(2)
res17: Int = 7scala> b.remove(2, 3)scala> b
res19: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2)scala> b.toArray
res20: Array[Int] = Array(1, 1, 2)scala> b.toBuffer
res22: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2)
scala> val c = b.toBuffer
c: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2)scala> c
res24: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2)scala> val c = b.toArray
c: Array[Int] = Array(1, 1, 2)scala> c
res25: Array[Int] = Array(1, 1, 2)

3.3 遍历数组和数组缓冲

for (i <- 0 until a.length)println(i + ": " + a(i))0 until 10 高带 0.until(10)0 until (a.length, 2)// Range(0, 2, 4, ...)0 until (a.length).reversefor (elem <- a)println(elem)

3.4 数组转换

scala> val a = Array(2, 3, 5, 7)
a: Array[Int] = Array(2, 3, 5, 7)scala> val result = for (elem <- a) yield 2 * elem
result: Array[Int] = Array(4, 6, 10, 14)// 从 数组缓冲 出发,也会得到另一个数组缓冲scala> for (elem <- a if elem % 2 == 0) yield 2 * elem
res26: Array[Int] = Array(4)scala> a
res27: Array[Int] = Array(2, 3, 5, 7)

函数式编程

scala> a.filter(_ % 2 == 0).map(2 * _)
res28: Array[Int] = Array(4)

考虑如下示例 :
给定一个整数的数组缓冲,我们想要移除除第一个负数之外的所有负数。

1). 收集保留的下标

var first = true
val indexs = for (i <- 0 until a.length if first || a(i) >= 0) yield { if (a(i) < 0) first = false; i }

2). 元素移动到该去的位置

for (j <- 0 until indexs.length) a(j) = a(indexs(j))
a.trimEnd(a.length - indexs.length)

3.5 常用算法

cala> Array(1, 7, 2).sum
res0: Int = 10// ArrayBuffer the samescala> Array(1, 7, 2).min
res1: Int = 1scala> Array(1, 7, 2).max
res2: Int = 7scala> Array(1, 7, 2.5).max
res4: Double = 7.0scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBufferscala> ArrayBuffer("Mary", "had", "little", "lamb").max
res9: String = little

sorted 方法将 Array or ArrayBuffer 排序并返回经过排序的 Array or ArrayBuffer

不改变原数组,产生新数组

scala> val b = ArrayBuffer(1, 7, 2, 9).sorted
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 7, 9)scala> val b = ArrayBuffer(1, 7, 2, 9).sortWith(_>_)
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(9, 7, 2, 1)

改变原数组

scala> val a = Array(1, 7, 2, 9)
a: Array[Int] = Array(1, 7, 2, 9)scala> scala.util.Sorting.quickSort(a)scala> a
res11: Array[Int] = Array(1, 2, 7, 9)

对于 min, max 和 quickSort 方法,元素类型必须支持比较操作, 这包括了数字、字符串以及其他带有 Ordered 特质的类型。

显示 Array 或 ArrayBuffer 的内容,用 mkString

scala> a.mkString
res12: String = 1279scala> a.mkString(",")
res13: String = 1,2,7,9scala> a.mkString("<", ",", ">")
res14: String = <1,2,7,9>scala> a.toString
res15: String = [I@6691eb1e

3.6 解读 Scaladoc

对 Array类 的操作方法列在 ArrayOps 相关条目下。从技术上讲,在数组上对用这些操作之前,数组都会被转换成 ArrayOps对象

3.7 多维数组

Double 的二维数组类型为 Array[Array[Double]]. 构造用 ofDim 方法。

scala> val matrix = Array.ofDim[Double](3, 4)
matrix: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0))scala> matrix(1)(2) = 42scala> matrix
res19: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 42.0, 0.0), Array(0.0, 0.0, 0.0, 0.0))

创建不规则数组

scala> val triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)scala> for (i <- 0 until triangle.length)|   triangle(i) = new Array[Int](i+1)scala> triangle
res21: Array[Array[Int]] = Array(Array(0), Array(0, 0), Array(0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))

3.8 与 Java 的互操作

可以引入 scala.collection.JavaConversions 里的隐式转换方法。

java.lang.ProcessBuilder类 有一个以 List<String> 为参数的构造器

import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBufferscala> val command = ArrayBuffer("ls", "-al", "/home/data0")
command: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(ls, -al, /home/data0)// Scala 到 Java 的转换
scala> val pb = new ProcessBuilder(command)
pb: ProcessBuilder = java.lang.ProcessBuilder@467eb8eb
import scala.collection.mutable.Buffer
import scala.collection.JavaConversions.asScalaBufferscala> val cmd: Buffer[String] = pb.command() // Java到Scala转换
cmd: scala.collection.mutable.Buffer[String] = ArrayBuffer(ls, -al, /home/data0)scala> command
res25: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(ls, -al, /home/data0)

Chap 4 映射和元组

focus on:

  1. Scala 有十分易用的语法来创建、查询、遍历映射

  2. 你需要从可变和不可变的映射中做出选择

  3. 默认你得到的是 哈希映射, 你也可以指明要 树形映射

  4. Scala映射 和 Java映射 之间来回切换

  5. 元组可以用来聚集值

4.1 构造映射

不可变的映射

scala> val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores: scala.collection.immutable.Map[String,Int] = Map(Alice -> 10, Bob -> 3, Cindy -> 8)

可变的映射

scala> val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores: scala.collection.mutable.Map[String,Int] = Map(Bob -> 3, Alice -> 10, Cindy -> 8)

new 空映射

scala> val scores = new scala.collection.mutable.HashMap[String, Int]
scores: scala.collection.mutable.HashMap[String,Int] = Map()

Scala 中,映射是对偶的集合。

scala> "Alice"->10
res26: (String, Int) = (Alice,10)scala> val scores = Map(("Alice", 10), ("Bob", 3))
scores: scala.collection.immutable.Map[String,Int] = Map(Alice -> 10, Bob -> 3)

4.2 获取映射中的值

scala> val bobsScore = scores("Bob")
bobsScore: Int = 3scala> val bobsScore = if (scores.contains("Bob")) scores("Bob") else 0
bobsScore: Int = 3scala> val bobsScore = if (scores.contains("Bob")) scores("Bobo") else 0
java.util.NoSuchElementException: key not found: Boboat scala.collection.MapLike$class.default(MapLike.scala:228)at scala.collection.AbstractMap.default(Map.scala:59)at scala.collection.MapLike$class.apply(MapLike.scala:141)at scala.collection.AbstractMap.apply(Map.scala:59)... 33 elidedscala> val bobsScore = if (scores.contains("Bobo")) scores("Bob") else 0
bobsScore: Int = 0scala> val bobsScore = scores.getOrElse("Bob", 0)
bobsScore: Int = 3  // 快捷写法

4.3 更新映射中的值

scala> val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores: scala.collection.mutable.Map[String,Int] = Map(Bob -> 3, Alice -> 10, Cindy -> 8)scala> scores("Bob")=10scala> val bobsScore = scores.getOrElse("Bob", 0)
bobsScore: Int = 10scala> scores("Kevin")=100scala> scores
res30: scala.collection.mutable.Map[String,Int] = Map(Bob -> 10, Kevin -> 100, Alice -> 10, Cindy -> 8)scala> scores += ("Bob"->90, "Fred"->7)
res31: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Alice -> 10, Cindy -> 8)scala> scores
res32: scala.collection.mutable.Map[String,Int] = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Alice -> 10, Cindy -> 8)scala> scores -= "Alice"
res33: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8)scala> scores
res34: scala.collection.mutable.Map[String,Int] = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8)scala> scores -= "Alice00"
res36: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8)

4.4 迭代映射

scala> scores.keySet
res40: scala.collection.Set[String] = Set(Bob, Kevin, Fred, Cindy)scala> scores.values
res46: Iterable[Int] = HashMap(90, 100, 7, 8)scala> for ((k, v) <- scores) yield { print (k, v) }
(Bob,90)(Kevin,100)(Fred,7)(Cindy,8)res42: scala.collection.mutable.Iterable[Unit] = ArrayBuffer((), (), (), ())scala> for ((k, v) <- scores) yield (v, k)
res45: scala.collection.mutable.Map[Int,String] = Map(8 -> Cindy, 100 -> Kevin, 7 -> Fred, 90 -> Bob)

4.5 已排序映射

操作映射的时候,你需要选定一个实现 : 哈希表 or 平衡树. default hashtable

得到一个不可变的树形映射,而不是哈希映射

scala> val scores = scala.collection.immutable.SortedMap("Alice" -> 10, "Fred" -> 7, "Bob" -> 3, "Cindy" -> 8)
scores: scala.collection.immutable.SortedMap[String,Int] = Map(Alice -> 10, Bob -> 3, Cindy -> 8, Fred -> 7)

可变的树形映射,选择 Java 的 TreeMap。

按照插入顺序访问所有的键,使用 scala 的 LinkedHashMap

4.6 与 Java 的互操作

Java映射 转换为 Scala映射

scala> import scala.collection.JavaConversions.mapAsScalaMap
import scala.collection.JavaConversions.mapAsScalaMapscala> val scores: scala.collection.mutable.Map[String, Int] = new java.util.TreeMap[String, Int]
scores: scala.collection.mutable.Map[String,Int] = Map()

java.util.Properties 到 Map[String, String] 的转换

scala> import scala.collection.JavaConversions.propertiesAsScalaMap
import scala.collection.JavaConversions.propertiesAsScalaMapscala> val props: scala.collection.Map[String, String] = System.getProperties()
props: scala.collection.Map[String,String] =
Map(env.emacs -> "", java.runtime.name -> Java(TM) SE Runtime Environment, sun.boot.library.path -> /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib, java.vm.version -> 24.79-b02, user.country.format -> CN, gopherProxySet -> false, java.vm.vendor -> Oracle Corporation, java.vendor.url -> http://java.oracle.com/, path.separator -> :, java.vm.name -> Java HotSpot(TM) 64.Bit Server VM, file.encoding.pkg -> sun.io, user.country -> US, sun.java.launcher -> SUN_STANDARD, sun.os.patch.level -> unknown, java.vm.specification.name -> Java Virtual Machine Specification, user.dir -> /Users/hp, java.runtime.version -> 1.7.0_79-b15, java.awt.graphicsenv -> sun.awt.CGraphicsEnvironment, java.endorsed.dirs -> /Library/Java/JavaVirtual...

Scala映射 传递给 预期 Java映射 的方法,提供相反的隐式转换

import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._scala> val attrs = Map(FAMILY -> "Serif", SIZE -> 12)
attrs: scala.collection.immutable.Map[java.awt.font.TextAttribute,Any] = Map(java.awt.font.TextAttribute(family) -> Serif, java.awt.font.TextAttribute(size) -> 12)以下方法预期一个 java映射
scala> val font = new java.awt.Font(attrs)
font: java.awt.Font = java.awt.Font[family=Serif,name=Serif,style=plain,size=12]scala> font
res47: java.awt.Font = java.awt.Font[family=Serif,name=Serif,style=plain,size=12]scala> attrs
res48: scala.collection.immutable.Map[java.awt.font.TextAttribute,Any] = Map(java.awt.font.TextAttribute(family) -> Serif, java.awt.font.TextAttribute(size) -> 12)

不是很明白 java互操作?

4.7 元组

映射是 key/value 对偶 的集合。 对偶 是 元组 tuple 最简单的形态。

scala> val t = (1, 3.14, "Hello")
t: (Int, Double, String) = (1,3.14,Hello)scala> val second = t._2
second: Double = 3.14scala> val (first, second, _) = t
first: Int = 1
second: Double = 3.14

元组的下标从 1 开始。

元组可以用于函数返回不止一个值的情况。举例来说, StringOps 的 partition 方法返回的是一对字符串,分别包含了满足某个条件和不满足该条件的字符

scala> val y1 = "New York".partition(_.isUpper)
y1: (String, String) = (NY,ew ork)

4.8 拉链操作

使用元组的原因之一是把多个值绑在一起,便于它们被一起处理。

scala> val symbols = Array("<", "-", ">")
symbols: Array[String] = Array(<, -, >)scala> val counts = Array(2, 10, 2)
counts: Array[Int] = Array(2, 10, 2)scala> val pairs = symbols.zip(counts)
pairs: Array[(String, Int)] = Array((<,2), (-,10), (>,2))scala> for ((s, n) <- pairs) Console.print(s * n)
<<---------->>

用 toMap 方法可以将对偶的集合转换成映射

scala> val pairs = symbols.zip(counts).toMap
pairs: scala.collection.immutable.Map[String,Int] = Map(< -> 2, - -> 10, > -> 2)

相关文章:

linux下使用NetBeans调试libevent库

1.安装libevent 参考&#xff1a;http://blog.csdn.net/unix21/article/details/8679269 libevent安装在usr/local/libevent下 2.安装netBeans http://www.netbeans.org 3.配置netBeans 1)打开项目的属性选项&#xff0c;选择包含目录&#xff0c;把/usr//local/libevent/…

批量删除指定文件

Linux下的解决方法: # Linux Batch Delete find /home/data/-name ab.doc-exec rm -f {} \;注&#xff1a;最后反斜杠前有一空格&#xff0c;最后一个是分号。Windows下的解决方法:rem Windows Batch Delete 1: DEL /Q /S D:\home\data\*.class 2: FOR /R D…

百万人学AI:CSDN重磅共建人工智能技术新生态

站在AI发展的新十年起点上&#xff0c;CSDN将发挥开发者优势&#xff0c;与中国AI各行业和企业共建“百万人学AI”新技术生态。 作者 | CSDN新媒体事业部 8年前&#xff0c;现图灵奖得主Hinton团队在ImageNet竞赛中首次使用深度学习完胜Google等其它团队&#xff0c;顿时让工…

Android Property Animation属性动画:scale缩放动画(4)

&#xfeff;&#xfeff;Android Property Animation属性动画&#xff1a;scale缩放动画&#xff08;4&#xff09; 和之前我写的附录文章1,2,3相似&#xff0c;本文将接着使用Android Property Animation属性动画实现一个缩放的动画。代码部分和文章1,2,3中的代码大同小异&am…

结构体的两种声明方式:堆上和栈上以及在双链表的应用

在看《算法精解&#xff1a;C语言描述》的双链表chtbl和redis的双链表adlist.c发现代码思路基本是一致的。 但是&#xff0c;对于链表的初始化却不一样 1.《算法精解&#xff1a;C语言描述》风格 /************************************************************************…

COM 组件设计与应用(六)——用 ATL 写第一个组件(vc.net)

一、前言 1、与 《COM 组件设计与应用(五)》的内容基本一致。但本回讲解的是在 vc.net 2003 下的使用方法&#xff0c;即使你不再使用vc6.0&#xff0c;也请和上一回的内容&#xff0c;参照比对。2、这第一个组件&#xff0c;除了所有 COM 组件必须的 IUnknown 接口外&#xff…

《评人工智能如何走向新阶段》后记(再续19)

由AI科技大本营下载自视觉中国304. 也来讨论构建模拟人类思维过程的认知计算机制&#xff0c;好像这个问题迄今尚未获得解决。 我们先从输入的信息类型说起&#xff1a;一类是语言输入&#xff08;包括词、句、文本&#xff09;&#xff0c;第二类是图像输入&#xff08;包括图…

PHP下载/采集远程图片到本地

2019独角兽企业重金招聘Python工程师标准>>> PHP下载/采集远程图片到本地01 /** 02* 下载远程图片到本地 03* 04* param string $url 远程文件地址 05* param string $filename 保存后的文件名&#xff08;为空时则为随机生成的文件名&#xff0c;否则为原文件名&am…

Linux守护进程实现

Linux守护进程 redis版&#xff1a; void daemonize(void) {int fd;if (fork() ! 0) exit(0); /* parent exits */setsid(); /* create a new session *//* Every output goes to /dev/null. If Redis is daemonized but* the logfile is set to stdout in the configuration …

美团十年,支撑最大规模外卖配送的一站式机器学习平台如何炼成?

作者 | 艳伟&#xff0c;美团配送技术团队资深技术专家编辑 | 唐小引题图 | 东方 ICAI 是目前互联网行业炙手可热的“明星”&#xff0c;无论是老牌巨头&#xff0c;还是流量新贵&#xff0c;都在大力研发 AI 技术&#xff0c;为自家的业务赋能。配送作为外卖平台闭环链条上重要…

Windows 2008 R2中的NAP新功能详解

随着Windows Server 2008 R2版本的发布&#xff0c;Windows网络访问保护模式&#xff08;NAP&#xff09;又增加了新功能。在本文中&#xff0c;笔者将对新功能进行简要的介绍。Windows Server 2008中提供的网络访问保护(NAP)功能已经更新到R2版本。在Windows功能、无线网络访问…

whoosh学习(1)

2019独角兽企业重金招聘Python工程师标准>>> 背景 当前项目需要用到全文搜索redis不方便实现mysql效率太低搜索引擎选择 pylucenewhoosh&#xff08;似乎更受欢迎&#xff0c;文档最全&#xff09;为什么选择 纯python实现&#xff0c;省了编译二进制包的繁琐过程。…

仿照redis写的nginx开机画面

redis有一个开机画面&#xff1a; 下面是我写的的nginx开机画面&#xff1a; 新建一个文件 asciilogo.h //仿照redis风格打印一个logo,这样启动的时候就不会不注意 char *ascii_logo " …

房子成焦点,被挂马的房产网站仍在增加中

统计发现&#xff0c;近期大部分使用极光漏洞挂马&#xff0c;这个漏洞实在是太好用了。没打补丁&#xff0c;没装网盾&#xff0c;按网马广告上说的&#xff0c;有不弹、不卡、不闪三大“优点”&#xff0c;点击挂马网页会中招。今天新增被挂马的知名房产网站列表&#xff08;…

检测、量化、追踪新冠病毒,基于深度学习的自动CT图像分析有多靠谱?

作者 | Ophir Gozes, Maayan Frid-Adar等译者 | 刘畅出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;背景&#xff1a;新冠病毒的传播非常迅速&#xff0c;并对数十亿人的生活产生了重大影响。由于非对称胸部CT已被证明是检测、量化和追踪该疾病的有效工具&#xff0…

关于产品体验以及产品会被抄袭的思考

一个好产品本来可以以免费让用户注册为开始吸引用户并从而能引导用户进行消费和购买的&#xff1b;但是由于可能考虑到当前这个产品可能会被别人抄袭&#xff0c;从而设定了门槛&#xff0c;然后营销团队进行沟通&#xff0c;和别人说当前的产品是多么多么的好&#xff0c;从而…

Linux socket 网络编程 常用头文件

一 三种类型的套接字&#xff1a;1.流式套接字&#xff08;SOCKET_STREAM)提供面向连接的可靠的数据传输服务。数据被看作是字节流&#xff0c;无长度限制。例如FTP协议就采用这种。2.数据报式套接字&#xff08;SOCKET_DGRAM&#xff09;提供无连接的数据传输服务&#xff0c;…

达摩院实现自动驾驶核心技术突破,达摩院首次实现3D物体检测精度与速度的兼得

阿里巴巴达摩院在自动驾驶3D物体检测领域取得了新突破&#xff01;达摩院近期一篇论文入选计算机视觉顶会CVPR 2020&#xff0c;该论文提出了一个通用、高性能的自动驾驶检测器&#xff0c;首次实现3D物体检测精度与速度的兼得&#xff0c;有效提升自动驾驶系统安全性能。目前&…

$httpprovider指令中拦截器interceptors的使用介绍

2019独角兽企业重金招聘Python工程师标准>>> $http服务允许我们使用http请求和后台做通信&#xff0c;但是在每一次放松请求之前我们都希望能够捕捉这个请求并且进行操作&#xff0c;比如之前富瑞中每一个请求中header要放入用户名和密码一样&#xff0c;富瑞的做法…

bzero, memset ,setmem 区别

bzero 原型&#xff1a;extern void bzero(void *s, int n);用法&#xff1a;#include <string.h> 功能&#xff1a;置字节字符串s的前n个字节为零。 说明&#xff1a;bzero无返回值。 举例&#xff1a; // bzero.c #include <sysl…

了解这4个重点,带你探索未来将如何设计智能系统和机器人!

作者 | Himanshu Ragtah 译者 | 天道酬勤 责编 | 徐威龙 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 到目前为止&#xff0c;为智能系统设计零件需要从头开始构建零件。从2D草图到可以根据给定的成本、材料和最大重量限制制造的可行且坚固的零件。这通常需要几天…

静态路由和默认路由的配置实例

RTA的配置&#xff1a;interface FastEthernet0/0ip address 1.1.1.2 255.255.255.252duplex autospeed auto!interface FastEthernet0/1no ip addressduplex autospeed autoshutdown!interface FastEthernet1/0ip address 10.10.10.1 255.255.255.0duplex autospeed auto!inte…

Centos运行级别和开机过程

一、Linux运行级别1&#xff09;0&#xff1a;关机2&#xff09;1&#xff1a;单用户3&#xff09;2&#xff1a;多用户状态没有网络服务4&#xff09;3&#xff1a;多用户状态有网络服务5&#xff09;4&#xff1a;系统未使用保留给用户6&#xff09;5&#xff1a;图形界面7&a…

PHP FPM设置

php-fpm启动 拷贝启用文件 # cp -R ./sapi/fpm/php-fpm /etc/init.d/php-fpm 启动 # /etc/init.d/php-fpm 重启 # killall php-fpm # /etc/init.d/php-fpm ------------------------ 进程不够就会起新&#xff0c;新的不能超过pm.max_children&#xff1b; 但是新的也会变为…

MySQL的binarylog处理

繁忙中測試新到的服務器&#xff0c;調試優化app&#xff0c;再加上月底公司搬家&#xff0c;很多配置都要更改。早上不經意telnet改dns的時候發現MySQL日誌很大了。。。 奇怪&#xff0c;我設置過的都改過了。。後來發現這台是子公司帶過來的機器。。。。以前那幾台都沒寫過配…

IJCAI 2020灭霸式拒稿,AI审稿是否更公平?

来源 | 数据派 THU编辑 | 文婧出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;一、IJCAI 2020灭霸式拒稿引众怒随着AAAI 2020于2月7日作为2020年人工智能学界的第一个顶会在美国纽约开幕&#xff0c;人工智能相关领域的研究者们又要为新一年的顶会忙碌了。对于AI界的…

ASP.NET MVC 中将FormCollection与实体间转换方法

http://blog.csdn.net/lutinghuan/article/details/8449296 将Action动作中传递的FormCollection转变成对应的实体&#xff0c;可以使用Controller的TryUpdateModel()方法。 示例如下&#xff1a; [csharp] view plaincopy [HttpPost] public ActionResult Create(FormCollect…

增量学习不只有finetune,三星AI提增量式少样本目标检测算法 | CVPR 2020

作者 | VincentLee来源 | 晓飞的算法工程笔记该论文研究了非常有意义的增量式少样本目标检测场景iFSD(Incremental Few-Shot Detection)&#xff0c;场景设置如下&#xff1a;检测模型可以在包含充足样本的基础类别上进行训练训练好后&#xff0c;iFSD能够应用到真实世界中&…

修改Linux内核参数提高服务器并发能力

1.参数设置 查看相关的参数 sysctl -a|grep tcp_keepalive net.ipv4.tcp_keepalive_intvl 30 net.ipv4.tcp_keepalive_probes 2 net.ipv4.tcp_keepalive_time 160 设置相关的参数 sysctl -w net.ipv4.tcp_keepalive_time 7500 也可以直接打开 # vim/etc/sysctl.conf 加入ne…

GPS小车移动应用程序

//用于desktop部署private void btnInitializeObjects_Click(object sender, System.EventArgs e){Catalog Cat MapInfo.Engine.Session.Current.Catalog; //创建临时层TableInfoMemTable tblInfoTemp new TableInfoMemTable("Animation");Table tblTemp Cat.GetT…