Scala中下划线用法和使用场景汇总(奇巧淫技)

thinkingfioa 2019-06-15

_(下划线)这个字符在 Scala 中似乎无处不在,到目前为止,它可能是 Scala 中使用最广泛的符号。

Scala中下划线用法和使用场景汇总(奇巧淫技)

使用场景清单:

一、用于替换Java的等价语法

1. 作为包引入的通配符

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

//Java

import java.util.*;

//Scala

import java.util._

即“引用包中的所有内容”。

2. 类成员默认值

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

class Person {

//String类型的默认值为null

String name;

}

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

class Person{

//String类型的默认值为null

var name: String = _

}

Scala中下划线用法和使用场景汇总(奇巧淫技)

在这里,name 也可以声明为null,例:var name:String=null。这里的下划线和null的作用是一样的。

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

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中,你必须要明确的告诉编译器,你是想将集合作为一个独立的参数传进去,还是想将集合的元素传进去。如果是后者则要借助下划线:

def printArgs(args: String*): Unit = {

for (elem <- args) {

System.out.println(elem + " ")

}

}

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

4. 类型通配符

Java的泛型系统有一个通配符类型,例如List<?>,任意的List<T>类型都是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 + " "))

}

调用代码:

printList(List("a","b","c"))

printList(List(1,2,3,4,5,6))

Scala中下划线用法和使用场景汇总(奇巧淫技)

二、模式匹配

2.1 默认匹配

str match{

case "1" => println("match 1")

case _ => println("match default")

}

最后一个case语句使用了通配符:_,相当于Java中的 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("hello", "rickie")

Scala中下划线用法和使用场景汇总(奇巧淫技)

Scala中下划线用法和使用场景汇总(奇巧淫技)

三、Scala特有语法

3.1 访问Tuple元素

val t = (1, 2, 3)

println(t._1, t._2, t._3)

Scala中下划线用法和使用场景汇总(奇巧淫技)

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

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

val f1 = (_: Int) + (_: Int)

//等价于

val f2 = (x: Int, y: Int) => x + y

Scala中下划线用法和使用场景汇总(奇巧淫技)

list.foreach(println(_))

//等价于

list.foreach(e => println(e))

Scala中下划线用法和使用场景汇总(奇巧淫技)

list.filter(_ > 0)

//等价于

list.filter(x => x > 0)

Scala中下划线用法和使用场景汇总(奇巧淫技)

val newArr = (1 to 10) map(_*2)

下划线代表了集合中的“某(this)”一个元素。这个用法很常见,在foreach等语句中也可以使用。

Scala中下划线用法和使用场景汇总(奇巧淫技)

3.3 定义一元操作符

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

-2

//等价于

2.unary_-

Scala中下划线用法和使用场景汇总(奇巧淫技)

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

Scala中下划线用法和使用场景汇总(奇巧淫技)

3.6 将方法转换成函数

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

先定义一个方法:m1

def m1(x:Int, y:Int):Int = x*y

Scala中下划线用法和使用场景汇总(奇巧淫技)

//将 m1 方法转换成函数,并赋值给 f1

val f1 = m1 _

Scala中下划线用法和使用场景汇总(奇巧淫技)

下划线在大部分的应用场景中是以语法糖的形式出现的,使Scala 代码显得更加简洁,但是对于不熟悉下划线用法的码农,代码阅读起来稍显困难,因此需要先了解一下。

相关推荐