Scala 中下划线的用途

本文详细介绍了Scala中下划线的各种应用场景,包括存在性类型、高阶类型参数、临时变量、临时参数等,并通过具体例子展示了下划线如何在函数式编程中提高代码的简洁性和可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: https://my.oschina.net/leejun2005/blog/405305

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/

Scala中,函数(function)和方法(method)是有一些区别的。 1. 定义方式:函数是通过`val`关键字定义的值,而方法是通过`def`关键字定义的类成员。 2. 形式:函数是一个独立的值,可以直接赋值给变量,作为参数传递给其他函数,或者作为返回值返回。方法则是属于类或对象的成员,需要通过实例或者类名来调用。 3. 参数列表:函数的参数列表可以用括号包裹,也可以省略括号。方法的参数列表总是需要用括号包裹。 4. 调用方式:函数可以直接使用参数列表调用,而方法需要通过对象或者类名来调用。 5. 带有副作用:函数通常是纯函数(pure function),即没有副作用的函数。方法可以有副作用,例如修改对象的状态或者打印输出等。 下面是一个示例来说明函数和方法的区别: ```scala // 定义函数 val add: (Int, Int) => Int = (x, y) => x + y // 定义类,并定义一个方法 class MyClass { def multiply(x: Int, y: Int): Int = x * y } // 创建类的实例 val obj = new MyClass() // 调用函数 val result1 = add(3, 4) println(result1) // 输出: 7 // 调用方法 val result2 = obj.multiply(3, 4) println(result2) // 输出: 12 ``` 需要注意的是,Scala中方法可以转换为函数,而函数不能直接转换为方法。可以使用方法引用(method reference)或者使用下划线(_)来将方法转换为函数。例如: ```scala val multiplyFunc: (Int, Int) => Int = obj.multiply val multiplyFunc2: (Int, Int) => Int = obj.multiply _ ``` 总的来说,函数和方法在Scala中有些许的差异,但在实际使用中,它们可以互相转换和配合使用,根据需要选择合适的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值