目录
方法的定义
默认参数
变长参数
过程
懒值(lazy)
方法VS函数
定义方式
表达形式
参数要求
方法和函数的相互转换
有以下几点需要注意:
scala> def m1(name : String, left : String = "<", right : String = ">") = {
| left + name + right
| }
m1: (name: String, left: String, right: String)String
scala> m1("hello")
res0: String =
scala> m1("hello","<<",">>")
res1: String = <>
scala> m1("hello", right = ">>")
res2: String = >
scala> m1("hello", "<<")
res3: String = <
说明:
可以在定义参数的时候直接为参数赋值;
当调用方法时,可以不设置已有默认值的参数;
可以设置默认参数的值,设置值的时候会按照方法默认参数的顺序依次设置,也可以指定参数名对其进行赋值。
当输入相同类型的参数个数无法确定时,可以使用变长参数,java和python中都有此特性
scala> def sum(args : Int*) = {
| var res = 0
| for(arg <- args) res += arg
| res
| }
sum: (args: Int*)Int
scala> sum(1,2,3,4)
res0: Int = 10
sum方法的参数类型是Seq类型,如果有一个值的序列不能传入变长参数中,此时会报错
scala> sum(1 to 4)
:13: error: type mismatch;
found : scala.collection.immutable.Range.Inclusive
required: Int
sum(1 to 4)
^
如果就是想传入一个已有序列,怎么办?scala设计之初肯定也是想过的,就是在出入的已有序列后追加“:_*”,表示将一个Range转成一个Seq
scala> sum(1 to 4 :_*)
res5: Int = 10
在Scala中,定义方法时,如果方法体直接包裹在了花括号里面,而没有使用=连接,则方法的返回值类型就是Unit。这样的方法就被称之为过程。过程通常用于不需要返回值的方法。过程还有一种写法,就是将方法的返回值类型定义为Unit。其实过程就是相当于Java中无返回值的方法。
//将方法主体直接包含在{}中,并省略“=”,其实方法是一个返回Unit类型的方法
scala> def hello(name : String){ print("hello," + name) }
hello: (name: String)Unit
scala> hello("liumingxin")
hello,liumingxin
即使我们在方法中依旧设置了返回值,过程返回值类型依旧是Unit
//即使设置了返回值,过程返回的依旧是Unit类型
scala> def hello(name : String){ print("hello," + name);"hello, " + name}
hello: (name: String)Unit
scala> hello("liumingxin")
hello,liumingxin
在Scala中,提供了lazy值的特性,也就是说,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用。
lazy的调用并不做任何额外的开销,每一次访问lazy值的时候,都会调用一个方法,以线程安全的方式检查该值是否已经被初始化了。
scala> val a = 1 / 0
java.lang.ArithmeticException: / by zero
... 28 elided
scala> lazy val a = 1 / 0
a: Int =
scala> a
java.lang.ArithmeticException: / by zero
at .a$lzycompute(:11)
at .a(:11)
... 28 elided
很明显,1/0是错误的,在不使用lazy的时候,创建变量直接报错;使用lazy之后,只有调用时才检查是否,如果创建了才进行调用。
在Spark中使用了大量的lazy。
Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait(Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。) 的类的对象。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。
//方法的定义
scala> def m1(x: Int) = x + 1
m1: (x: Int)Int
//函数的定义
scala> val f1 = (x : Int) => x + 1
f1: Int => Int = $$Lambda$1036/961708482@1573e8a5
方法是一个以def开头的带有参数列表(可以无参数列表)的一个逻辑操作块,这正如object或者class中的成员方法一样。(上面有定义说明)
函数是一个赋值给一个变量(或者常量)的匿名方法(带或者不带参数列表),并且通过=>转换符号跟上逻辑代码块的一个表达式。=>转换符号后面的逻辑代码块的写法与method的body部分相同。
scala> m1
:13: error: missing argument list for method m1
Unapplied methods are only converted to functions when a function type is expect
ed.
You can make this conversion explicit by writing `m1 _` or `m1(_)` instead of `m
1`.
m1
^
scala> f1
res1: Int => Int = $$Lambda$1036/961708482@1573e8a5
method(带参方法)不能作为最终的表达式(无参方法可以,但是这个就成了方法调用,因为scala允许无参方法调用时省略()括号)。
function可以作为最终的表达式出现。
方法名意味着方法调用,函数名只是代表函数自身。
scala> def m2 = 100
m2: Int
scala> def m3() = 100
m3: ()Int
scala> val f2=() => 100
f2: () => Int = $$Lambda$1050/1002690318@78bce1c4
scala> val f3= => 100
:1: error: illegal start of simple expression
val f3= => 100
^
方法可以没有参数列表页可以是空的参数列表。
函数必须设置参数列表,可以是空的参数列表,但一定要设置。
把 x => func(x) 简化为 func _ 或 func 的过程称为 eta-conversion(函数转换成方法)
把 func 或 func _ 展开为 x => func(x) 的过程为 eta-expansion(方法转换成函数)
可以在方法名后面加一个下划线强制变成函数,方法名与下划线之间至少有一个空格,没有会报错
eta-expansion过程:
//方法转变成函数 ETA-expansion,记得方法名与_之间加空格
scala> val f4 = m1
:12: error: missing argument list for method m1
Unapplied methods are only converted to functions when a function type is expect
ed.
You can make this conversion explicit by writing `m1 _` or `m1(_)` instead of `m
1`.
val f4 = m1
^
scala> val f4 = m1_
:11: error: not found: value m1_
val f4 = m1_
^
scala> val f4 = m1 _
f4: Int => Int = $$Lambda$1054/2011547493@5daa621b
eta-conversion过程:
//ETA-conversion,也验证了m4是一个方法,并不是一个函数
scala> def m4(x : Int) = f1(x)
m4: (x: Int)Int
scala> m4
:13: error: missing argument list for method m4
Unapplied methods are only converted to functions when a function type is expect
ed.
You can make this conversion explicit by writing `m4 _` or `m4(_)` instead of `m
4`.
m4
^