重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这期内容当中小编将会给大家带来有关Scala 方法和函数的区别是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
成都创新互联公司是一家以成都网站建设公司、网页设计、品牌设计、软件运维、营销推广、小程序App开发等移动开发为一体互联网公司。已累计为成都服务器托管等众行业中小客户提供优质的互联网建站和软件开发服务。
Scala中既有函数(Function)也有方法(Method),大多数情况下我们都可以不去理会他们之间的区别。但是有时候我们必须要了解他们之间的不同。
Scala 中的方法跟 Java 的方法一样,方法是组成类的一部分。方法有名字、类型签名,有时方法上还有注解,以及方法的功能实现代码(字节码)。
Scala 中的函数是一个完整的对象。Scala 中用 22 个特质(trait)抽象出了函数的概念。这 22 特质从 Function1 到 Function22:
如上图中的 Function10 代表的是:有 10 个形参,返回值为 R(协变)的函数。
函数更常使用的是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要名称如果你要是用的话,一般会把这个匿名函数赋值给一个变量(其实是val常量)
表现形式:(传入参数)=>{方法体}
val f = (name:String)=>println("Hi,"+name) f("kafka")
Scala 中的函数其实就是继承了这些 Trait 的类的对象,如:我们通过函数字面量定义一个函数
其实上述函数的定义方式跟如下定义方式等同:
由于 Function2 是特质,不能直接 new。上述 new Function2[Int,Int,Int](){} 其实是定义并实例化一个实现了 Function2 特质的类的对象。
apply 是 scala 中的语法糖:对一个对象 obj 上调用 obj(),scala 编译器会转换为 obj.apply();在一个类 clazz 上调 clazz(),scala 编译器会转换为 clazz_company_obj.apply(),其中 clazz_company_obj 为 clazz 的伴生对象。
具体的差异,总结为如下几点:
1. 方法不能作为单独的表达式而存在(参数为空的方法除外),而函数可以。如:
scala> def m(x:Int) = 2.0*x m: (x: Int)Double 方法的定义 scala> val f = (x:Int)=> 2.0*x f: Int => Double =函数定义 scala> f res7: Int => Double = 函数就是 scala> val tmp = m _ 通过这个方式还可以实现方法到函数的变化 tmp: Int => Double = scala> m 直接调用方法名是错误的 :13: error: missing argument list for method m Unapplied methods are only converted to functions when a function type is expected. You can make this conversion explicit by writing `m _` or `m(_)` instead of `m`. m ^ 在Scala语言中, 函数也是对象, 每一个对象都是scala.FunctionN(1-22)的实例, 其中N是函数参数的数量, 例如我们定义一个函数并复制给一个变量: scala> val f = (x: Int) => x + 1 (匿名函数的写法) f: Int => Int = 这里定义了一个接收一个整型变量作为参数的函数, 函数的功能是返回输入参数加1. 可以看到REPL返回参数的toString方法 即 . 那么如果我们有一个指向函数对象的引用, 我们该如何调用这个函数呢? 答案是通过FunctionN的 apply 方法, 即 FunctionN.apply() , 因此调用函数对象的方法如下: scala> f.apply(3) res2: Int = 4 但是如果每次调用方法对象都要通过FunctionN.apply(x, y...), 就会略显啰嗦, Scala提供一种模仿函数调用的格式来调用函数对象 scala> f(3) res3: Int = 4
在如上的例子中,我们首先定义了一个方法 m,接着有定义了一个函数f。接着我们把函数名(函数值)当作最终表达式来用,由于f本身就是一个对象(实现了 FunctionN 特质的对象),所以这种使用方式是完全正确的。但是我们把方法名当成最终表达式来使用的话,就会出错。
2.方法可以没有参数列表而 函数必须要有参数列表
scala> def m1 = 100 m1: Int 没有入参的方法定义 是下面的简写形式 scala> def m2() = 100 m2: ()Int 无入参的放到定义 scala> val f1 = ()=>100 无入参的函数定义 f1: () => Int =scala> val f1 = => 100 仿照最上面写就直接报错 :1: error: illegal start of simple expression val f1 = => 100
在如上的例子中,m1方法接受零个参数,所以可以省略参数列表。而函数不能省略参数列表。
3.方法名是方法调用,而函数名只是代表函数对象本身
这个比较容易理解。因为保存函数字面量的变量(又称为函数名或者函数值)本身就是实现了 FunctionN 特质的类的对象,要调用对象的 apply方法,就需要使用obj()的语法。所以函数名后面加括号才是调用函数。如下:
scala> def m1 = 100 m1: Int 方法定义 scala> val f1 = ()=> 100 函数定义 f1: () => Int =scala> m1 方法调用 res11: Int = 100 scala> f1 函数查看 res12: () => Int = scala> f1() 函数调用,是下面调用方式的简单版 res13: Int = 100 scala> f1.apply() 函数调用的正确形式 res14: Int = 100
4.在需要函数的地方,如果传递一个方法,会自动进行ETA展开(把方法转换为函数)
如上,如果我们直接把一个方法赋值给变量会报错。如果我们指定变量的类型就是函数,那么就可以通过编译,如下:
scala> val f1:(Int)=>Int = m f1: Int => Int =
当然我们也可以强制把一个方法转换给函数,这就用到了 scala 中的部分应用函数:
scala> val f1 = m _ f1: Int => Int =scala> val f1 = m(_) f1: Int => Int =
5.传名参数本质上是个方法
传名参数实质上是一个参数列表为空的方法,因为函数的话参数列表是不能为空的!(区别2参考),如下:
scala> def m1(x: =>Int) = List(x,x) m1: (x: => Int)List[Int]
如上代码实际上定义了一个方法 m1,m1 的参数是个传名参数(方法)。由于对于参数为空的方法来说,方法名就是方法调用 ,所以List(x,x)实际上是进行了两次方法调用。
由于 List(x,x) 是进行了两次方法调用,所以得到两个不同的值。如果我们稍微修改一下函数的m1的定义,把x先缓存起来,结果就会跟以前大不一样。
scala> def m1(x: => Int) = {val y = x;List(y,y)} m1: (x: => Int)List[Int] scala> m1(r.nextInt) res18: List[Int] = List(-723271792, -723271792)
6. 方法跟函数当参数的调用
// 方法定义 def method1(arge1: Int, arge2: Int) = arge1 + arge2 // 函数定义 val funct1 = (arge1: Int, arge2: Int) => arge1 - arge2 def method2(f: (Int, Int) => Int) = f(12, 12) println("方法传方法" + method2(method1)) val funct2 = (f: (Int, Int) => Int) => f(22, 22) println("函数传方法" + funct2(method1)) def method3(f: (Int, Int) => Int) = f(4, 1) println("方法传函数" + method3(funct1)) val funct3 = (f: (Int, Int) => Int) => f(5, 1) println("函数传函数" + funct3(funct1)) -------------------------------------------------------------------------------------- // 调用方式一 方法调用方法 def method1(): Unit = println("printmethod1") def method2(m: () => Unit): Unit = m() // 如果参数列表写的是带() 调用的时候也要带() method2(method1) //执行 // 调用方式二 方法调用方法 def method11: Unit = println("printmethod11") def method22(m: => Unit) = m // 如果参数列表中 就没有() 此处不可写m() method22(method11) //执行 //调用方式三 def method111(): Unit = println("printmethod111") def method222(m: () => Unit) = m // 如果参数列表带() 调用时候不带(),则不会执行 method222(method111) //此处没有输出
Scala 中Apply讲解
class ApplyTest{ def apply() = println("I am into Spark so much!!!") def haveATry{ println("Have a try on apply!") } } object ApplyTest{ def apply() = { println("I am into Scala so much!!!") new ApplyTest } } object ApplyOperation { def main(args: Array[String]) { val array = Array(1,2,3,4,5) val a = ApplyTest() //这里并没有new,然后确实返回了类的实例 a.haveATry } }
输出结果:
I am into Scala so much!!! Have a try on apply!
在一个类的伴生对象里面,实现apply方法,在这里面可以创建类的实例。譬如val a = Array(1, 2, 3)就是使用了Array的apply方法。
同样,在class里面也可以使用apply方法:
object ApplyOperation { def main(args: Array[String]) { val a = new ApplyTest a.haveATry println(a()) //调用class的apply方法 } }
结果:
Have a try on apply! I am into Spark so much!!! ()
上述就是小编为大家分享的Scala 方法和函数的区别是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注创新互联行业资讯频道。