scala 中方法和函数的区别

 我来答
从空去听8
2017-11-16 · TA获得超过7441个赞
知道大有可为答主
回答量:6907
采纳率:93%
帮助的人:5610万
展开全部

在Scala中函数和方法有什么区别

方法可以作为一个表达式的一部分出现(调用函数并传参),但是方法(带参方法)不能作为最终的表达式,

但是函数可以作为最终的表达式出现:

scala> //定义一个方法scala> def m(x:Int) = 2*x
m: (x: Int)Int

scala> //定义一个函数scala> val f = (x:Int) => 2*x
f: Int => Int = <function1>scala> //方法不能作为最终表达式出现scala> m<console>:9: error: missing arguments for method m;
follow this method with `_‘ if you want to treat it as a partially applied function              m              ^scala> //函数可以作为最终表达式出现scala> f
res9: Int => Int = <function1>

无参方法可以作为最终表达式出现,其实这属于方法调用,scala规定无参函数的调用可以省略括号

(关于方法调用我们下面会涉及到)

scala> def m1()=1+2m1: ()Int

scala> m1
res10: Int = 3

参数列表对于方法是可选的,但是对于函数是强制的

方法的可以没有参数列表,参数列表也可以为空。但是函数必须有参数列表(也可以为空),见下面例子

scala> //方法可以没有参数列表scala> def m2 = 100;
m2: Int

scala> //方法可以有一个空的参数列表scala> def m3() = 100m3: ()Int

scala> //函数必须有参数列表,否则报错scala> var f1 =  => 100
<console>:1: error: illegal start of simple expression
var f1 =  => 100
^scala> //函数也可以有一个空的参数列表scala> var f2 = () => 100f2: () => Int = <function0>

那么方法为什么可以没有参数列表呢,往下看。

方法名意味着方法调用,函数名只是代表函数自身

因为方法不能作为最终的表达式存在,所以如果你写了一个方法的名字并且该方法不带参数(没有参数列表或者无参)

该表达式的意思是:调用该方法得到最终的表达式。因为函数可以作为最终表达式出现,如果你写下函数的名字,函数

调用并不会发生,该方法自身将作为最终的表达式进行返回,如果要强制调用一个函数,你必须在函数名后面写()

scala> //该方法没有参数列表scala> m2
res11: Int = 100scala> //该方法有一个空的参数列表scala> m3
res12: Int = 100scala> //得到函数自身,不会发生函数调用scala> f2
res13: () => Int = <function0>scala> //调用函数scala> f2()
res14: Int = 100

为什么在函数出现的地方我们可以提供一个方法

在scala中很多高级函数,如map(),filter()等,都是要求提供一个函数作为参数。但是为什么我们可以提供一个方法呢

?就像下面这样:

scala> val myList = List(3,56,1,4,72)
myList: List[Int] = List(3, 56, 1, 4, 72)

scala> // map()参数是一个函数scala> myList.map((x) => 2*x)
res15: List[Int] = List(6, 112, 2, 8, 144)

scala> //尝试给map()函提供一个方法作为参数scala> def m4(x:Int) = 3*x
m4: (x: Int)Int

scala> //正常执行scala> myList.map(m4)
res17: List[Int] = List(9, 168, 3, 12, 216)

这是因为,如果期望出现函数的地方我们提供了一个方法的话,该方法就会自动被转换成函数。该行为被称为ETA expansion。

这样的话使用函数将会变得简单很多。你可以按照下面的代码验证该行为:

scala> //期望出现函数的地方,我们可以使用方法scala>  val f3:(Int)=>Int = m4
f3: Int => Int = <function1>scala> //不期望出现函数的地方,方法并不会自动转换成函数scala> val v3 = m4<console>:8: error: missing arguments for method m4;
follow this method with `_‘ if you want to treat it as a partially applied function
val v3 = m4                ^

利用这种自动转换,我们可以写出很简洁的代码,如下面这样

scala> //10.<被解释成obj.method,即整形的<的方法,所以该表达式是一个方法,会被解释成函数scala> myList.filter(10.<)
res18: List[Int] = List(56, 72)

因为在scala中操作符被解释称方法

  • 前缀操作符:op obj 被解释称obj.op

  • 中缀操作符:obj1 op obj2被解释称obj1.op(obj2)

  • 后缀操作符:obj op被解释称obj.op

  • 你可以写成10<而不是10.<

  • scala> myList.filter(10<)

  • warning: there were 1 feature warning(s); re-run with -feature for details

  • res19: List[Int] = List(56, 72)

  • 如何强制把一个方法变成函数

    可以在方法名后面加一个下划线强制变成函数,部分应用函数

  • scala> val f4 = m4 _

  • f4: Int => Int = <function1>scala> f4(2)

  • res20: Int = 6

  • 传名参数是一个方法

    传名参数实质是一个没有参数列表的方法。正是因此你才可以使用名字调用而不用添加()

  • scala> //使用两次‘x‘,意味着进行了两次方法调用scala> def m1(x: => Int)=List(x,x)

  • m1: (x: => Int)List[Int]


  • scala> import util.Randomimport util.Random


  • scala> val r = new Random()

  • r: scala.util.Random = scala.util.Random@d4c330b


  • scala> //因为方法被调用了两次,所以两个值不相等scala> m1(r.nextInt)

  • res21: List[Int] = List(-1273601135, 2004676878)

  • 如果你在方法体部分缓存了传名参数(函数),那么你就缓存了值(因为x函数被调用了一次)

  • scala> //把传名参数代表的函数缓存起来scala> def m1(x: => Int) ={val y=x;List(y,y)}

  • m1: (x: => Int)List[Int]


  • scala> m1(r.nextInt)

  • res22: List[Int] = List(-1040711922, -1040711922)

  • 能否在函数体部分引用传名参数所代表的方法呢,是可以的(缓存的是传名参数所代表的方法)。

  • scala> def m1(x: => Int)={val y=x _;List(y(),y())}

  • m1: (x: => Int)List[Int]


  • scala> m1(r.nextInt)

  • res23: List[Int] = List(-1982925840, -933815401)

推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式