前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Play For Scala 开发指南 - 第2章 Scala基本语法

Play For Scala 开发指南 - 第2章 Scala基本语法

作者头像
joymufeng
发布2018-05-17 15:56:33
6370
发布2018-05-17 15:56:33
举报
2.1 运行Scala代码

感谢Scala.js项目,我们可以在浏览器中运行Scala代码。点击ScalaFiddle开始我们的Scala之旅吧!

2.2 Scala的特性

每一种编程语言的存在都有意义,Scala存在的意义是为了让那些热爱编程的人更加热爱编程。Scala的设计简洁而优雅,很多地方都彰显了编程语言的一致性,例如在Scala的世界里:

 一切都是对象

你可以直接调用基本类型上的方法:

1.toDouble     // 1.0
10.toHexString // a
"1".toInt      // 1

 一切都是方法

在Scala中其实没有+-*/这些运算符,它们其实是基本类型上的方法。例如String类型上的*方法用于将当前字符串重复n次并拼接为一个新的字符串:

"a".*(3) // "aaa"

但是这种写法可读性很糟糕,如果方法只包含一个参数,那么你可以省略"."和"()",写成:

"a" * 3 // "aaa"

这样看起来是不是舒服多了。不止是String类型,你可以重新定义任何类型上的*方法。

在调用Scala对象上的方法时,变量名和方法名中间的点"."可以省略,进一步,如果方法只包含一个参数,则参数两边的括号"()"可以省略。在后面我们会发现,利用这两个语法糖,我们可以自定义一些特殊语法,并且让它们看起来像是编程语言提供的功能。

 一切都是表达式

任何语句都会一个返回值,编译器会自动帮你推断返回值类型:

val i = if(true){ 1 } else { 0 } // i = 1

Scala拥有一套强大的类型推导系统,你可以像动态类型语言那样编码,大大降低了代码的冗余度,同时也增强了代码的可读性。

很多人在刚开始学习Scala时就被一些奇怪的符号吓到,其实当你明白其背后的设计用意后,你不但不会觉得它可怕,反而会觉得有点可爱。举个例子,很多人看到Scala使用::拼接元素,使用:::拼接列表,就像下面这样:

val list1 = List("c", "a", "l", "a")
val list2 = s :: list1 // list2: (s, c, a, l, a)
val list3 = List("p", "l", "a", "y")
val list4 = list3 ::: list2 // list4: (p, l, a, y, s, c, a, l, a)

我们之前说过在Scala里一切都是方法,所以::和:::自然也是方法,只不过是为了简洁,省略了.和()。在Scala中列表List被设计成由head和tail拼接在一起的递归结构(这种设计在模式匹配时非常有用), List的定义可以写成如下形式:

head :: tail

head是首元素,tail是剩余的List。仔细瞧瞧::看起来是不是很像胶水,将列表的头和尾紧紧地粘在一起,更进一步:::可以把两个列表粘在一起。这样的代码是不是很简洁,并且富有表达力呢! 在Scala中,类似这样的设计比比皆是,例如我们再来看看如何构建一个Map实例:

val map = Map("name" -> "PlayScala社区", "url" -> "http://www.playscala.cn")

感受一下,是不是非常清晰明了。 当然Scala的魅力远不止如此,当你慢慢了解它时,你会慢慢深陷而无法自拔。

2.3 Hello, Scala

让我们从经典的Hello, World开始:

package txt

object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello, Scala")
  }
}

在Scala中,程序的入口是object对象,object对象无须实例化可以直接运行,你可以认为它是Java的单例对象。执行的入口方法是main函数,参数是一个字符串数组,main方法的返回类型是Unit,Unit表示一个无值类型,类似于Java的void方法。println方法用于向控制台输出内容。

Scala的泛型类型使用"[]"而不是像Java那样使用"<>",因为在Scala中"<"和">"是有效的方法名,它们有更重要的用途。

2.4 变量声明

val用于定义不可变变量,var用于定义可变变量,这里的"可变"指的是引用的可变性。val定义的变量类似于Java的final变量,即变量只能赋一次值:

val msg = "hello" // 等价于:val msg: String = "hello"
var i = 1         // 等价于:var   i: Int = 1 
i = i + 1

为了方便阅读,定义变量时也可以显式指定其类型:

val msg: String = "hello"
var i: Int = 1

因为变量类型是可忽略的,所以放在了变量名后面。后面我们会发现Scala的类型信息都放在后面,采用类型后置语法。

变量后面的类型声明可以省略,每行代码末尾的分号";"也可以省略。

2.5 函数声明

函数支持是Scala语言的最大亮点,相对于Java的Lambda和函数式接口,你可以享受到原生的函数式编程。关键字def用于定义函数:

def max(x: Int, y: Int): Int = {
    if (x > y) { x } else { y }
}
val maxVal = max(1, 2) // 2

Scala不建议在函数体内使用return语句,因为过多的return会使得代码逻辑混乱。Scala默认使用函数体的最后一个表达式作为返回值。当然你仍然可以使用return语句指定返回值。

你可以像基本类型那样把函数赋给一个变量:

val max = (x: Int, y: Int) => {
    if (x > y) { x } else { y }
}
val maxVal = max(1, 2) // 2

等号"="右边是一个匿名函数,也就是我们常说的Lambda函数,匿名函数由参数和函数体两部分组成,中间用"=>"隔开,这里省略了max变量的类型,因为编译器可以自动推断出来,完整的写法如下:

val max: (Int, Int) => Int = (x: Int, y: Int) => {
    if (x > y) { x } else { y }
}

max的类型是(Int, Int) => Int,即接受两个Int参数,产生一个Int返回值的函数类型。

2.6 控制结构

if语法结构和Java很像,区别是Scala的if是表达式,可以返回一个值:

val i = if(true){ 1 } else { 0 } // i = 1

while循环的语法如下:

while (n > 0) {
  println(n)
  n -= 1
}

for语法结构为:

for (i <- 1 to 10) {
  println(i)
}

1 to 10等价于1.to(10),返回包含数字1到10的Range类型。

2.7 class

Scala的class定义和Java很相似:

class Counter {
  private var value = 0 
  def increment() { value += 1} //方法可见性默认public
  def current() = value 
}

类成员(属性和方法)的可见性默认为public。

Scala的源文件中可以定义多个类,并且默认都是public,所以外界都可以看见。class的使用也很简单:

val myCounter = new Counter //或new Counter()
myCounter.increment()
println(myCounter.current)  //或myCounter.current()

Scala中如果对象方法或类的构造器没有参数,则括号"()"可以省略。

Scala会为所有的属性生成相应可见性的setter和getter方法,例如:

class Person{
  var age = 0
}

编译器会自动为age属性生成setter和getter方法,方法名分别为age_=和age:

println(p.age) // 将会调用方法p.age()
p.age = 30     // 将会调用方法p.age=(30)

在Scala中,setter/getter方法名未采用setXxx/getXxx格式,如果需要Java风格的setXxx/getXxx格式可以使用@BeanProperty注解。

当然你也可以重新定义setter和getter方法:

class Person{
  private var privateAge = 0
  
  def age = privateAge
  def age_=(newValue: Int) {
    privateAge = newValue
  }
}
2.8 object

Scala没有静态方法和静态字段,而是提供了object对象,也就是Java中的单例对象,即全局只有一个实例:

object Accounts {
    private var lastNumber = 0
    def newUniqueNumber() = { lastNumber += 1; lastNumber }
}

因为Accounts是一个单例对象,可以直接使用而无需初始化:

val uniqueNumber = Accounts.newUniqueNumber

object的另一个用法是作为类的伴生对象, 类似于Java类上的静态方法,只不过Scala将Java类上的静态功能全交给object实现。object作为伴生对象时必须和类在同一个源文件中定义,并且可以相互访问私有属性。

2.9 apply方法

如果某个对象obj上定义了apply方法,则我们可以这样调用:

obj(arg1, ... , argn)

是的,你猜对了,伴生对象上的apply方法立马就派上用场了,例如List类有一个同名的伴生对象List,那么你可以这样初始化一个列表:

val list = List("a", "b", "c")

想想下面的Java版本,是不是感觉幸福感油然而生:

List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
2.10 块表达式

在Scala中一切都是表达式,如果表达式含有多条语句,则使用大括号"{}"括起来,形成一个块表达式,块表达式的最后一条语句的值作为整个块的返回值。

val r = {    
  val i = 1
  val j = 2
  i + j
} // r = 3
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.1 运行Scala代码
  • 2.2 Scala的特性
  • 2.3 Hello, Scala
  • 2.4 变量声明
  • 2.5 函数声明
  • 2.6 控制结构
  • 2.7 class
  • 2.8 object
  • 2.9 apply方法
  • 2.10 块表达式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档