这期内容当中小编将会给大家带来有关Scala 方法和函数的区别是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
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 = <function1> 函数定义 scala> f res7: Int => Double = <function1> 函数就是 scala> val tmp = m _ 通过这个方式还可以实现方法到函数的变化 tmp: Int => Double = <function1> scala> m 直接调用方法名是错误的 <console>: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 = <function1> 这里定义了一个接收一个整型变量作为参数的函数, 函数的功能是返回输入参数加1. 可以看到REPL返回参数的toString方法 即 <function0> . 那么如果我们有一个指向函数对象的引用, 我们该如何调用这个函数呢? 答案是通过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 = <function0> scala> val f1 = => 100 仿照最上面写就直接报错 <console>: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 = <function0> scala> m1 方法调用 res11: Int = 100 scala> f1 函数查看 res12: () => Int = <function0> scala> f1() 函数调用,是下面调用方式的简单版 res13: Int = 100 scala> f1.apply() 函数调用的正确形式 res14: Int = 100
4.在需要函数的地方,如果传递一个方法,会自动进行ETA展开(把方法转换为函数)
如上,如果我们直接把一个方法赋值给变量会报错。如果我们指定变量的类型就是函数,那么就可以通过编译,如下:
scala> val f1:(Int)=>Int = m f1: Int => Int = <function1>
当然我们也可以强制把一个方法转换给函数,这就用到了 scala 中的部分应用函数:
scala> val f1 = m _ f1: Int => Int = <function1> scala> val f1 = m(_) f1: Int => Int = <function1>
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 方法和函数的区别是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。