精彩文章免费看

Scala中Method方法和Function函数的区别

本文将列出一些常见的区别与联系
基本的区别

在Scala中方法不是值,而函数是。所以一个方法不能赋值给一个val变量,而函数可以。

scala> def increment(n: Int) = n + 1
increment: (n: Int)Int
scala> val fun = increment
<console>:12: error: missing argument list for method increment
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `increment _` or `increment(_)` instead of `increment`.
       val fun = increment

在这个例子中定义了一个方法increment,然后将这个方法赋值给变量fun失败。根据提示,可以通过将方法转化为函数的方式实现。

scala> val fun = increment _
fun: Int => Int = <function1>

有时候根据上下文编译器可以自动将方法转换为函数,而不需要使用下划线

scala> List(1,2,3).map(increment)
res0: List[Int] = List(2, 3, 4)
scala> List(1,2,3).map(increment _)
res1: List[Int] = List(2, 3, 4)

重载的影响

scala> object Tool{
     | def increment(n: Int): Int = n + 1
     | def increment(n: Int, step: Int): Int = n + step
defined object Tool
scala> val fun = Tool.increment _
<console>:12: error: ambiguous reference to overloaded definition,
both method increment in object Tool of type (n: Int, step: Int)Int
and  method increment in object Tool of type (n: Int)Int
match expected type ?
       val fun = Tool.increment _

将方法转换为函数的时候,如果方法有重载的情况,必须指定参数和返回值的类型

scala> val fun1 = Tool.increment _ : (Int => Int)
fun1: Int => Int = <function1>
scala> List(1, 2, 3).map(fun1)
res0: List[Int] = List(2, 3, 4)
scala> val fun2 = Tool.increment _ : ((Int, Int) => Int)
fun2: (Int, Int) => Int = <function2>
scala> List(1, 2, 3).map(fun2(_, 5))
res1: List[Int] = List(6, 7, 8)

参数相关问题

  • 无参数方法
    对于一个无参数的方法是没有参数列表的,而对于函数是有一个空参数列表。
  • scala> def x = println("Hi scala")
    x: Unit //没有参数列表
    scala> val y = x _
    y: () => Unit = <function0> //空的参数列表()
    scala> y()
    Hi scala
    scala> x
    Hi scala
    
  • 多个参数的方法可以转换为多元函数
  • scala> def plus(x: Int, y: Int): Int = x + y
    plus: (x: Int, y: Int)Int
    scala> plus _
    res1: (Int, Int) => Int = <function0>
    
  • 多个参数的方法变成柯里函数
  • scala> def plus(x: Int)(y: Int): Int = x + y
    plus: (x: Int)(y: Int)Int
    scala> plus _
    res1: Int => (Int => Int) = <function1>
    

    plus方法只能同时传入两个参数才能执行,分步执行会报错

    scala> plus(2)(3)
    res2: Int = 5
    scala> plus(2)
    <console>:15: error: missing argument list for method plus
    Unapplied methods are only converted to functions when a function type is expected.
    You can make this conversion explicit by writing `plus _` or `plus(_)(_)` instead of `plus`.
           plus(2)
    

    如果要分步执行,必须转化为函数

    scala> val fun = plus(2) _
    fun: Int => Int = <function1>
    scala> fun(3)
    res3: Int = 5
    
  • 类型参数(Type Parameters)
    在Scala中的值是不能有类型的,所以如果将带有类型的方法转换为函数,必须指定具体的参数类型
  • scala> def id[T] (x : T): T = x
    id: [T](x: T)T
    scala> val fun = id _ //没有指定T的具体类型
    fun: Nothing => Nothing = <function1>
    scala> fun(5)
    <console>:14: error: type mismatch;
     found   : Int(5)
     required: Nothing
           fun(5)
    scala> val fun = id[Int] _ //要转化为函数必须指定T的具体类型
    fun: Int => Int = <function1>
    scala> fun(5)
    res1: Int = 5
    
  • By-Name参数(By-Name Parameters
    必须是函数才能作为值使用,例如:
  • scala> def test(x: =>Unit): ()=>Unit = x 
    <console>:11: error: type mismatch;
     found   : Unit
     required: () => Unit
           def test(x: =>Unit): ()=>Unit = x
    scala> def test(x: =>Unit): ()=>Unit = x _ //必须是函数才能作为test的返回值
    test: (x: => Unit)() => Unit
    scala> val fun = test(println("Hi scala"))
    fun: () => Unit = <function0>
    scala> fun()
    Hi scala
    
  • 序列参数(Sequence Parameters)
    对于一个方法,可以使用参数序列,但是如果转换成函数之后,要使用Seq对象
  • scala> def exec(as: Int*): Int = as.sum
    exec: (as: Int*)Int
    scala> exec(1, 2, 3)
    res0: Int = 6
    scala> def fun = exec _ //转换为函数
    fun: Seq[Int] => Int
    scala> fun(1, 2, 3)
    <console>:14: error: too many arguments for method apply: (v1: Seq[Int])Int in trait Function1
           fun(1, 2, 3)
    scala> fun(Seq(1, 2, 3)) //必须使用Seq对象
    res2: Int = 6
    
  • 默认参数(Default Arguments)
    方法是支持参数默认值的用法,但是函数会忽略参数默认值的,所以函数不能省略参数
  • scala> def exec(s: String, n: Int = 2) = s * n
    exec: (s: String, n: Int)String
    scala> exec("Hi") //第二个参数使用了默认值
    res0: String = HiHi
    scala> val fun = exec _
    fun: (String, Int) => String = <function2>
    scala> fun("Hi") //无法使用默认值,不能省略参数
    <console>:14: error: not enough arguments for method apply: (v1: String, v2: Int)String in trait Function2.
    Unspecified value parameter v2.
           fun("Hi")
    scala> fun("Hi", 2) //必须设置所有参数
    res2: String = HiHi
    scala> fun("Hi", 3) //必须设置所有参数
    res3: String = HiHiHi