浅谈 Scala 中下划线的用途

Scala 作为一门函数式编程语言,对习惯了指令式编程语言的同学来说,会不大习惯,这里除了思维方式之外,还有语法层面的,比如 underscore(下划线)就会出现在多种场合,令初学者相当疑惑,今天就来总结下 Scala 中下划线的用法。

1、存在性类型:Existential types
def foo(l: List[Option[_]]) = ...

2、高阶类型参数:Higher kinded type parameters
case class A[K[_],T](a: K[T])

3、临时变量:Ignored variables
val _ = 5

4、临时参数:Ignored parameters
List(1, 2, 3) foreach { _ => println("Hi") }

5、通配模式:Wildcard patterns
Some(5) match { case Some(_) => println("Yes") }
match {
     case List(1,_,_) => " a list with three element and the first element is 1"
     case List(_*)  => " a list with zero or more elements "
     case Map[_,_] => " matches a map with any key type and any value type "
     case _ =>
 }
val (a, _) = (1, 2)
for (_ <- 1 to 10)

6、通配导入:Wildcard imports
import java.util._

7、隐藏导入:Hiding imports
// Imports all the members of the object Fun but renames Foo to Bar
import com.test.Fun.{ Foo => Bar , _ }

// Imports all the members except Foo. To exclude a member rename it to _
import com.test.Fun.{ Foo => _ , _ }

8、连接字母和标点符号:Joining letters to punctuation
def bang_!(x: Int) = 5

9、占位符语法:Placeholder syntax
List(1, 2, 3) map (_ + 2)
_ + _   
( (_: Int) + (_: Int) )(2,3)

val nums = List(1,2,3,4,5,6,7,8,9,10)

nums map (_ + 2)
nums sortWith(_>_)
nums filter (_ % 2 == 0)
nums reduceLeft(_+_)
nums reduce (_ + _)
nums reduceLeft(_ max _)
nums.exists(_ > 5)
nums.takeWhile(_ < 8)

10、偏应用函数:Partially applied functions
def fun = {
    // Some code
}
val funLike = fun _

List(1, 2, 3) foreach println _

1 to 5 map (10 * _)

//List("foo", "bar", "baz").map(_.toUpperCase())
List("foo", "bar", "baz").map(n => n.toUpperCase())

11、初始化默认值:default value
var i: Int = _

12、作为参数名:
//访问map
var m3 = Map((1,100), (2,200))
for(e<-m3) println(e._1 + ": " + e._2)
m3 filter (e=>e._1>1)
m3 filterKeys (_>1)
m3.map(e=>(e._1*10, e._2))
m3 map (e=>e._2)

//访问元组:tuple getters
(1,2)._2

13、参数序列:parameters Sequence 
_*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理。例如val s = sum(1 to 5:_*)就是将1 to 5当作参数序列处理。
//Range转换为List
List(1 to 5:_*)

//Range转换为Vector
Vector(1 to 5: _*)

//可变参数中
def capitalizeAll(args: String*) = {
  args.map { arg =>
    arg.capitalize
  }
}

val arr = Array("what's", "up", "doc?")
capitalizeAll(arr: _*)

这里需要注意的是,以下两种写法实现的是完全不一样的功能:

foo _               // Eta expansion of method into method value

foo(_)              // Partial function application

Example showing why foo(_) and foo _ are different:

trait PlaceholderExample {
  def process[A](f: A => Unit)

  val set: Set[_ => Unit]

  set.foreach(process _) // Error 
  set.foreach(process(_)) // No Error
}

In the first case, process _ represents a method; Scala takes the polymorphic method and attempts to make it monomorphic by filling in the type parameter, but realizes that there is no type that can be filled in for A that will give the type (_ => Unit) => ? (Existential _ is not a type).

In the second case, process(_) is a lambda; when writing a lambda with no explicit argument type, Scala infers the type from the argument that foreach expects, and _ => Unit is a type (whereas just plain _ isn't), so it can be substituted and inferred.

This may well be the trickiest gotcha in Scala I have ever encountered.

Refer:

[1] What are all the uses of an underscore in Scala?

http://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala

[2] Scala punctuation (AKA symbols and operators)

http://stackoverflow.com/questions/7888944/scala-punctuation-aka-symbols-and-operators/7890032#7890032

[3] Scala中的下划线到底有多少种应用场景?

http://www.zhihu.com/question/21622725

[4] Strange type mismatch when using member access instead of extractor

http://stackoverflow.com/questions/9610736/strange-type-mismatch-when-using-member-access-instead-of-extractor/9610961

[5] Scala简明教程

http://colobu.com/2015/01/14/Scala-Quick-Start-for-Java-Programmers/

[6] Scala入门到精通——第二十三节 高级类型 (二)

https://yq.aliyun.com/articles/60371#

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ACM算法日常

字符串展开(递归)- HDU 1274

常用纱线的品种一般不会超过25种,分别可以用小写字母表示不同的纱线,例如:abc表示三根纱线的排列;重复可以用数字和括号表示,例如:2(abc)表示abcabc...

10520
来自专栏一“技”之长

Swift讲解专题九——枚举 原

        在Objective-C语言中,没有实际上是整型数据,Swift中的枚举则更加灵活,开发者可以不为其分配值类型把枚举作为独立的类型来使用,也可以...

7620
来自专栏司想君

JavaScript闭包,只学这篇就会了

昨天发的文章,排版出现了重大失误。让大家的眼睛受累了。今天再发一遍。 这篇文章使用一些简单的代码例子来解释JavaScript闭包的概念,即使新手也可以轻松参透...

29380
来自专栏较真的前端

前端面试题“七连击”(一)

22370
来自专栏小詹同学

LeetCode 系列——双指针问题 。

关于 LeetCode 系列有段时间没有逐题更新了 ,还是想到一题一题的刷有些凌乱 。如前段时间的推文所说 ,准备系统的讲讲数据结构相关知识点 。

31020
来自专栏老马说编程

(30) 剖析StringBuilder / 计算机程序的思维逻辑

上节介绍了String,提到如果字符串修改操作比较频繁,应该采用StringBuilder和StringBuffer类,这两个类的方法基本是完全一样的,它们的实...

21260
来自专栏坚毅的PHP

python的数学函数(1)-python组合函数模块itertools

要解决的问题: 输出n个 ['A','T','C','G'] 所有的排列组合。 比如n=2 时,输出为 AA,AT,AC,AG,TA,TT,TC,TG,……...

41540
来自专栏轮子工厂

6. 简单又复杂的“运算符”,建议你看一哈

昨天的《5. 很“迷”的字符与字符串》初稿本来很短的,但是我觉得内容太少了,就加了一些,结果好像就变得特别多〒▽〒。

11030
来自专栏青玉伏案

在Objective-C中浅谈面向对象

  接触面向对象也有一段时间了,当时是通过C++学习的OOP,后来又接触到了PHP和Java。每种OOP的语言在面向对象上或多或少都会有不同的地方,现在在学习O...

20260
来自专栏黑泽君的专栏

java基础学习_面向对象(下)02_day09总结

============================================================================= ==...

10020

扫码关注云+社区

领取腾讯云代金券