1 import导入包的所有成员,相当于java的*,而*在scala中可以作为合法的identifier。比java方便的一点是它可以导入某个类下的所有静态成员,java则需要import static。
2 占位符:这个用法比较多,表示某一个参数。比如对collection或sequence调用方法map、filter、sortWith、foreach等等表示对每一个元素进行处理,甚至可以使用http://_.XXX方式;还有参数推导时f(250*_),假设已知f的参数类型是Int=>Int的函数类型时,可以在匿名函数中250*_使用_表示Int 参数,还比如val f = 250 * (_: Int);在模式匹配中根据unapply来初始化变量或集合时,如果不关心变量的某个具体属性或集合的某些元素则使用_来忽略,比如val Array(first, second, _*) = arr,只将arr的前2个值分别赋给first和second,这在match case class中用得比较多。
3 访问tuple变量的某个元素时通过索引_n来取得第n个元素
4 向函数或方法传入可变参数时不能直接传入Range或集合或数组对象,需要使用:_*转换才可传入
5 类的setter方法,比如类A中定义了var f,则相当于定义了setter方法f_=,当然你可以自己定义f_=方法来完成更多的事情,比如设置前作一些判断或预处理之类的操作
6 用于将方法转换成函数,比如val f=sqrt _,以后直接调用f(250)就能求平方根了
7 下划线_代表的是某一类型的默认值。比如var i:Int=_
对于Int来说,它是0。
对于Double来说,它是0.0
对于引用类型,它是null。
由于大部分的Java关键字在Scala中拥有了新的含义,所以一些基本的语法在Scala中稍有变化。
*在Scala中是合法的方法名,所以导入包时要使用_代替。
//Java
import java.util.*;
//Scala
import java.util._
Java中类成员可以不赋初始值,编译器会自动帮你设置一个合适的初始值:
class Foo{
//String类型的默认值为null
String s;
}
而在Scala中必须要显式指定,如果你比较懒,可以用_让编译器自动帮你设置初始值:
class Foo{
//String类型的默认值为null
var s: String = _
}
该语法只适用于类成员,而不适用于局部变量。
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"): _*)
Java的泛型系统有一个通配符类型,例如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 + " "))
}
str match{
case "1" => println("match 1")
case _ => println("match default")
}
//匹配以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")
public static void printList(List> list){
for(Object elem: list){
System.out.println(elem + " ");
}
}
val t = (1, 2, 3)
println(t._1, t._2, t._3)
如果函数的参数在函数体内只出现一次,则可以使用下划线代替:
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中的负数就是用左置操作符实现的
-2
//等价于
2.unary_-
我们通过下划线实现赋值操作符,从而可以精确地控制赋值过程:
class Foo {
def name = { "foo" }
def name_=(str: String) {
println("set name " + str)
}
}
val m = new Foo()
m.name = "Foo" //等价于: m.name_=("Foo")
我们可以为某个函数只提供部分参数进行调用,返回的结果是一个新的函数,即部分应用函数。因为只提供了部分参数,所以部分应用函数也因此而得名。
def sum(a: Int, b: Int, c: Int) = a + b + c
val b = sum(1, _: Int, 3)
b: Int => Int =
b(2) //6
Scala中方法和函数是两个不同的概念,方法无法作为参数进行传递,也无法赋值给变量,但是函数是可以的。在Scala中,利用下划线可以将方法转换成函数:
//将println方法转换成函数,并赋值给p
val p = println _
//p: (Any) => Unit