Scala 方法和函数的区别是什么

发布时间:2021-07-27 18:25:43 作者:Leah
来源:亿速云 阅读:167

这期内容当中小编将会给大家带来有关Scala 方法和函数的区别是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

Scala中既有函数(Function)也有方法(Method),大多数情况下我们都可以不去理会他们之间的区别。但是有时候我们必须要了解他们之间的不同。

Scala 中的方法跟 Java 的方法一样,方法是组成类的一部分。方法有名字、类型签名,有时方法上还有注解,以及方法的功能实现代码(字节码)。

Scala 中的函数是一个完整的对象。Scala 中用 22 个特质(trait)抽象出了函数的概念。这 22 特质从 Function1 到 Function22:

Scala 方法和函数的区别是什么

如上图中的 Function10 代表的是:有 10 个形参,返回值为 R(协变)的函数。

函数更常使用的是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要名称如果你要是用的话,一般会把这个匿名函数赋值给一个变量(其实是val常量) 
 表现形式:(传入参数)=>{方法体}

val f = (name:String)=>println("Hi,"+name)
 f("kafka")

Scala 中的函数其实就是继承了这些 Trait 的类的对象,如:我们通过函数字面量定义一个函数

Scala 方法和函数的区别是什么

 其实上述函数的定义方式跟如下定义方式等同:

Scala 方法和函数的区别是什么

由于 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 方法和函数的区别是什么

如上,如果我们直接把一个方法赋值给变量会报错。如果我们指定变量的类型就是函数,那么就可以通过编译,如下:

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)实际上是进行了两次方法调用。

Scala 方法和函数的区别是什么

由于 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 方法和函数的区别是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. Scala的方法和函数
  2. scala

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

scala

上一篇:torch.unsqueeze()和torch.squeeze()函数如何使用

下一篇:torch.mul()函数的作用是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》