下划线这个符号几乎贯穿了任何一本Scala编程书籍,并且在不同的场景下具有不同的含义,绕晕了不少初学者。正因如此,下划线这个特殊符号无形中增加Scala的入门难度。本文希望帮助初学者踏平这个小山坡。

1. 用于替换Java的等价语法

由于大部分的Java关键字在Scala中拥有了新的含义,所以一些基本的语法在Scala中稍有变化。

1.1 导入通配符

*在Scala中是合法的方法名,所以导入包时要使用_代替。

//Java
import java.util.*;

//Scala
import java.util._

1.2 类成员默认值

Java中类成员可以不赋初始值,编译器会自动帮你设置一个合适的初始值:

class Foo{
     //String类型的默认值为null
     String s;
}

而在Scala中必须要显式指定,如果你比较懒,可以用_让编译器自动帮你设置初始值:

class Foo{
    //String类型的默认值为null
    var s: String = _
}

该语法只适用于类成员,而不适用于局部变量。

1.3 可变参数

Java声明可变参数如下:

public static void printArgs(String ... args){
    for(Object elem: args){
        System.out.println(elem + " ");
    }
}

调用方法如下:

 //传入两个参数
printArgs("a", "b");
//也可以传入一个数组
printArgs(new String[]{"a", "b"});

在Java中可以直接将数组传给printArgs方法,但是在Scala中,你必须要明确的告诉编译器,你是想将集合作为一个独立的参数传进去,还是想将集合的元素传进去。如果是后者则要借助下划线:

printArgs(List("a", "b"): _*)

1.4 类型通配符

Java的泛型系统有一个通配符类型,例如List<?>,任意的List类型都是List<?>的子类型,如果我们想编写一个可以打印所有List类型元素的方法,可以如下声明:

public static void printList(List<?> list){
    for(Object elem: list){
        System.out.println(elem + " ");
    }
}

对应的Scala版本为:

def printList(list: List[_]): Unit ={
   list.foreach(elem => println(elem + " "))
}

2 模式匹配

2.1 默认匹配

str match{
    case "1" => println("match 1")
    case _   => println("match default")
}

2.2 匹配集合元素

//匹配以0开头,长度为三的列表
expr match {
  case List(0, _, _) => println("found it")
  case _ =>
}

//匹配以0开头,长度任意的列表
expr match {
  case List(0, _*) => println("found it")
  case _ =>
}

//匹配元组元素
expr match {
  case (0, _) => println("found it")
  case _ =>
}

//将首元素赋值给head变量
val List(head, _*) = List("a")

3. Scala特有语法

3.1 访问Tuple元素

val t = (1, 2, 3)
println(t._1, t._2, t._3)

3.2 简写函数字面量(function literal)

如果函数的参数在函数体内只出现一次,则可以使用下划线代替:

val f1 = (_: Int) + (_: Int)
//等价于
val f2 = (x: Int, y: Int) => x + y

list.foreach(println(_))
//等价于
list.foreach(e => println(e))

list.filter(_ > 0)
//等价于
list.filter(x => x > 0)

3.3 定义一元操作符

在Scala中,操作符其实就是方法,例如1 + 1等价于1.+(1),利用下划线我们可以定义自己的左置操作符,例如Scala中的负数就是用左置操作符实现的:

-2
//等价于
2.unary_-

3.4 定义赋值操作符

我们通过下划线实现赋值操作符,从而可以精确地控制赋值过程:

   class Foo {
      def name = { "foo" }
      def name_=(str: String) {
        println("set name " + str)
   }

    val m = new Foo()
    m.name = "Foo" //等价于: m.name_=("Foo")

3.5 定义部分应用函数(partially applied function)

我们可以为某个函数只提供部分参数进行调用,返回的结果是一个新的函数,即部分应用函数。因为只提供了部分参数,所以部分应用函数也因此而得名。

def sum(a: Int, b: Int, c: Int) = a + b + c
val b = sum(1, _: Int, 3)
b: Int => Int = <function1>
b(2) //6

3.6 将方法转换成函数

Scala中方法和函数是两个不同的概念,方法无法作为参数进行传递,也无法赋值给变量,但是函数是可以的。在Scala中,利用下划线可以将方法转换成函数:

//将println方法转换成函数,并赋值给p
val p = println _
//p: (Any) => Unit

4. 小结

下划线在大部分的应用场景中是以语法糖的形式出现的,可以减少击键次数,并且代码显得更加简洁。但是对于不熟悉下划线的同学阅读起来稍显困难,希望通过本文能够帮你解决这个的困惑。本文成文仓促,如有遗漏,欢迎留言! 转载请注明作者: joymufeng

Scala基础 - 下划线使用指南的更多相关文章

  1. scala的下划线

    1.作为“通配符”,类似Java中的*.如import scala.math._ 2.:_*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理!例如val s = sum(1 to 5:_*)就 ...

  2. Scala中 下划线的用处

    From:   http://congli.iteye.com/blog/2169401 1.作为“通配符”,类似Java中的*.如import scala.math._ 2.:_*作为一个整体,告诉 ...

  3. Scala _ 下划线

    1.引入包中的全部方法 import math._ //引入包中所有方法,与java中的*类似 2.表示集合元素 val a = (1 to 10).filter(_%2==0).map(_*2) / ...

  4. scala下划线

    作为函数的参数 一个匿名的函数传递给一个方法或者函数的时候,scala会尽量推断出参数类型.例如一个完整的匿名函数作为参数可以写为 scala> def compute(f: (Double)= ...

  5. scala 基础语法

    文章内容全部来自:http://twitter.github.io/scala_school/zh_cn/index.html 表达式 scala> 1 + 1 res0: Int = 2 值 ...

  6. 【转】Scala基础知识

    原文地址.续 课程内容: 关于这节课 表达式 值 函数 类 继承 特质 类型 apply方法 单例对象 函数即对象 包 模式匹配 样本类 try-catch-finally 关于这节课 最初的几个星期 ...

  7. scala中的下划线_

    1.作为“通配符”,类似Java中的*. 例如 import scala.math._ 2.:_*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理! 例如 val s = sum(1 to 5 ...

  8. Scala下划线_使用

    下划线这个符号几乎贯穿了任何一本Scala编程书籍,并且在不同的场景下具有不同的含义,绕晕了不少初学者.正因如此,下划线这个特殊符号无形中增加Scala的入门难度.本文希望帮助初学者踏平这个小山坡. ...

  9. Scala中_(下划线)的常见用法

    Scala中_(下划线)的常见用法 地址:https://www.jianshu.com/p/0497583ec538

随机推荐

  1. 抛弃vue-resource拥抱axios

    vue-resource用法 import Vue from 'vue' import VueResource from 'vue-resource' Vue.use(VueResource) 是不是 ...

  2. js华氏度转为摄氏度

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Asp.net SignalR 应用并实现群聊功能 开源代码

    ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务 ...

  4. Tomcat源码分析(一)

    这段时间简单的看了一下Tomcat的源码,在这里做个笔记!   1. tomcat 架构图 Catalina: tomcat的顶级容器,main()方法中就是通过,创建Catalina 对象实例,来启 ...

  5. Python之路-操作系统&网络基础

    一.为何要有操作系统 没有操作系统的话,计算机同样可以运行,但是程序员要了解到计算机底层各种各样的细节,而操作系统聪明地封装起来了底层这些繁杂的操作,通过向程序员开放一个个的接口,来最终使我们实现对底 ...

  6. 学习面向对象编程OOP 第二天

    好,今天继续学习这个面向对象编程.(根据博客园 小炒花生米写的博客学习而来) 一,封装性 a.把对象的全部属性和全部服务(方法)结合在一起,形成一个不可分割的独立单元 =>对象 b.信息隐蔽,尽 ...

  7. mac的终端为什么会显示git:(master),如何取消掉?

    今天在终端误操作,在主目录下执行git init命令,结果杯具了, 总是出现这个提示. 各种搜索解决方案,终于退出了. 方法如下: 删掉.git目录: rm -rf ~/.git

  8. 跟着刚哥梳理java知识点——变量之间的类型转换(四)

    变量之间的类型转换主要包括自动类型转换和强制类型转换. 1.自动类型转换:当容量小的数据类型与容量大的数据类型做运算时,容量小的会自动的转换成容量大的类型. [知识点]: a)char,byte,sh ...

  9. 谱聚类(Spectral clustering)(2):NCut

    作者:桂. 时间:2017-04-13  21:19:41 链接:http://www.cnblogs.com/xingshansi/p/6706400.html 声明:欢迎被转载,不过记得注明出处哦 ...

  10. js原型对象

    原型对象是什么? 在js中,每一个创建的的函数都会有一个prototype属性,这个属性指向一个对象,这个对象就是原型对象 function lla(){} console.log(lla.proto ...