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
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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容