专注于快乐的事情

Scala基本语法

本文于1500天之前发表,文中内容可能已经过时。

Scala的命令行工具

编写源码

upper1.sc的文件内容

class Upper {
  def upper(strings: String*): Seq[String] = {
    strings.map((s:String) => s.toUpperCase())
  }
}

val up = new Upper
println(up.upper("Hello", "World!"))

编译为 JVM 的字节码

将脚本文件编译为 JVM 的字节码(一组 .class 文件)
Scala 编译器叫作 scalac

执行
scalac -Xscript Upper1 src/main/scala/progscala2/introscala/upper1.sc
会发现当前文件夹下产生很多class文件

  1. Scala生成的代码,文件夹目录与包结构吻合。

执行脚本

scala Upper1
ArrayBuffer(HELLO, WORLD!)

scala src/main/scala/progscala2/introscala/upper1.sc

  1. 假如在命令行输入 scala 命令时不指定文件参数,REPL 将启动
  2. 假如输入 scala 命令时指定 Scala 源文件,scala 命令将会以脚本的形式编译并运行文件
  3. sbt 中执行console任务也能进入 Scala REPL 环境)
  4. 如果有参数scala -cp . progscala2.introscala.Upper Hello World!

逆向工程

java逆向工程

javap -cp . Upper1

scala逆向工程

scalap -cp . Upper1

object Upper1 extends scala.AnyRef {
  def this() = { /* compiled code */ }
  def main(args: scala.Array[scala.Predef.String]): scala.Unit = { /* compiled code */ }
}

基本语法解释

再次回到代码

class Upper {
  def upper(strings: String*): Seq[String] = {
    strings.map((s:String) => s.toUpperCase())
  }
}

val up = new Upper
println(up.upper("Hello", "World!"))
  1. 使用def创建函数,def后面依次为,输入方法名称以及可选的参数列表。再输入可选的返回类型。有时候,Scala 能够推导出返回类型。
  2. 返回类型由冒号加类型表示。最后使用等于号(=)将方法签名和方法体分隔开。
    String 类型后面的 * ,代表了变长的 String 类型参数列表。

    Scala 使用方括号([…])表示参数类型,而 Java 使用角括号(<…>)。

  3. val关键字用于声明不变变量book。可变数据是错误之源,推荐使用不变值。

  4. 使用println方法时,无需调用scala.Console.println方法。

    println 方法只是众多被自动加载的方法和类型中的一员,有一个叫作 Predef 的库对象对这些自动加载的方法和类型进行定义。

开发一个main函数

object Upper {
  def main(args: Array[String]) = {
    args.map(_.toUpperCase()).foreach(printf("%s ",_))
    println("")
  }
}
  1. 在 Scala 中,main 方法必须为对象方法。(在 Java 中,main 方法必须是类静态方法。)
  2. 两处使用了 _,这两个 _ 分别位于不同的作用域中,彼此之间没有任何关联

为什么使用等号呢?而不像 Java 那样,使用花括号表示方法体呢?

使用等号也强调了函数式编程的一个准则:值和函数是高度对齐的概念。
假如方法体仅包含一个表达式,那么 Scala 允许你省略花括号。所以说,使用等号能够避免可能的解析歧义。

函数字面量

map 方法的输入参数为函数字面量(function literal)。
strings.map((s:String) => s.toUpperCase())
而这些函数字面量便是“匿名”函数。在其他语言中,它们也被称为 Lambda、闭包(closure)、块(block)或过程(proc)
函数有很多表达式,可以使用{}来格式化代码,匿名函数也可以,

 { i: Int =>
  println("hello world")
  i * 2
}

此函数字面量的参数表中只包含了一个字符串参数 s。它的函数体位于箭头=>之后。该函数体调用了 s 的 UpperCase() 方法。此次调用的返回值会自动被这个函数字面量返回。

在 Scala 中,函数或方法中把最后一条表达式的返回值作为自己的返回值。尽管 Scala 中存在 return 关键字,但只能在方法中使用,上面这样的匿名函数则不允许使用。事实上,方法中也很少用到这个关键字。

函数的简写

(s:String) => s.toUpperCase()
等价如下函数
_.toUpperCase()

使用占位符 _ 来替代命名参数。也就是说:_ 起到了匿名参数的作用,在调用 toUpperCase 方法之前,_ 将被字符串替换。Scala 同时也为我们推断出了该变量的类型为 String 类型。

操作符

a + b 是如下方法调用的简写: a.+(b)
Scala 并不支持三元表达式,因为有一元操作。

遍历

while (n > 0) { rr = r * n n -= 1 }

for (i <- 1 to 3; j <- 1 to 3 if i != j) print ((10 * i + j) + “ “)

<-右边的表达式的所有值,至于这个遍历具体如何执行,则取决于表达式的类型
在Scala中,每个表达式都有一个类型
当 for 推导式仅包含单一表达式时使用原 括号,当其包含多个表达式时使用大括号

Scala 的 for 推导式并不提供 break 和 continue 功能。Scala 提供的其他特性 使得这两个功能没有存在的必要,那么如果需要break时我们该怎么做呢?有如下几个选项:

  1. 使用Boolean型的控制变量。

  2. 使用嵌套函数——你可以从函数当中return。

  3. 使用Breaks对象中的break方法:

基本集合

数组

基本定义

10个整数的数组,所有元素初始化为0
val nums = new ArrayInt

greetStrings为val, 但是内部的数组值是可变的
val greetStrings = new ArrayString

长度为2的Array[String]——类型是推断出来的
val s = Array(“Hello”, “World”)

循环

val b = new Array[String](10)
for (i <- 0 until b.length)   println(i + ": " + b(i))
for (i <- (0 until b.length).reverse) println(i + ": " + b(i))
for (elem <- b)   println(elem)//打印值
for (elem <- b if elem % 2 == 0) yield 2 +elem //改变数据 for使用了if

使用()而不是[]来访问元素,[]和java<>的类型相同,泛型类型。
对Array类的操作方法列在ArrayOps相关条目下

List

val numbers = List(1, 2, 3, 4)

对于List最常用的操作符为::, 把新的elem放到list最前端

scala> val numbers = List(1, 2, 3, 4)
numbers: List[Int] = List(1, 2, 3, 4)

scala> var numbers2 = 7::numbers
numbers2: List[Int] = List(7, 1, 2, 3, 4)

:::, 两个list的合并

val oneTwo = List(1, 2)
val threeFour = List(2,3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour
scala> val oneTwoThreeFour = oneTwo ::: threeFour
oneTwoThreeFour: List[Int] = List(1, 2, 2, 3, 4)

Set

var myset = Set(1, 1, 2)

元组 Tuple

val hostPort = (“localhost”, 80)

元组不能通过名称获取字段,而是使用位置下标来读取对象;而且这个下标基于1,而不是基于0
hostPort._1

与模式匹配

hostPort match {
  case ("localhost", port) => ...
  case (host, port) => ...
}

创建两个元素的元组时,可以使用特殊语法:->

scala>  1 -> 2
res1: (Int, Int) = (1,2)

Map

val treasureMap = MapInt, String

val myMap = Map(“foo” -> “bar”)
myMap(“foo”)

val numbers = Map(1 -> “one”, 2 -> “two”)
numbers.get(2)

函数组合子(Functional Combinators)

被用在标准的数据结构上

map

map对列表中的每个元素应用一个函数,返回应用后的元素所组成的列表。
foreach
filter
zip
partition
find
参考https://code.csdn.net/DOC_Scala/scala_class_twitter/file/%E9%9B%86%E5%90%88.md#anchor_0

其他

如果想使用数值类型,记得看看RichInt、RichDouble等。同理,如果想使用字符串,记得看看SpringOps。

那些数学函数位于scala.math包中,而不是位于某个类中

参考网站

评论系统未开启,无法评论!