Scala 下划线的用途

转载自 Scala基础 - 下划线使用指南 @joymufeng

用户替换Java的等价语法

导入通配符

1
2
3
4
5
// Java
import java.util.*;

// Scala
import java.util._

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

类成员默认值

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

自动设置类成员变脸的默认值。

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

可变参数

Java声明可变参数如下:

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

调用方法如下:

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

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

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

类型通配符

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

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

对应的Scala版本为:

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

模式匹配

默认匹配

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

匹配集合元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//匹配以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")

Scala特有语法

访问Tuple元素

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

简写函数字面量(function literal)

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

1
2
3
4
5
6
7
8
9
10
11
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)

定义一元操作符

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

1
2
3
-2
//等价于
2.unary_-

定义赋值操作符

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

1
2
3
4
5
6
7
8
class Foo {
def name = { "foo" }
def name_=(str: String) {
println("set name " + str)
}

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

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

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

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

将方法转换成函数

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

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

注:

  • 方法和函数的不同:
    • 方法是一个以def开头的带有参数列表的一个逻辑操作块,比如object或者class的成员方法
    • 函数是一个赋值给一个变量(或者常量)的匿名方法,并且通过=>转换符号跟上逻辑代码块的一个表达式
感谢你对我的支持,让我继续努力分享有用的技术和知识点