首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >匿名函数和部分函数有什么区别?

匿名函数和部分函数有什么区别?
EN

Stack Overflow用户
提问于 2020-08-22 18:59:27
回答 3查看 492关注 0票数 0

我读到了scala匿名函数这里,并看到它们可以采用这种格式:

代码语言:javascript
复制
{ case p1 => b1 … case pn => bn }

然而,我认为这就是部分函数的编写方式。实际上,在这篇博客文章中,作者将部分函数称为匿名函数。起初,他说collect接受一个部分函数,但后来似乎称它为匿名函数("collect可以处理匿名函数.“)。

只是某些匿名函数是部分函数吗?如果是的话,部分函数都是匿名的吗?或者只有在像阿尔文·亚历山大( Alvin Alexander)的例子这样的格式下,它们才是匿名的:

代码语言:javascript
复制
val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-08-23 00:06:37

从您链接的模式匹配匿名函数的文档中:

如果期望的类型是SAM-可转换为scala.Functionk[S1,…,Sk, R],则表达式将被视为等效于匿名函数: (x1:S1,…,xk:Sk) => (x1,…),xk)匹配{ case p1 => b1…案例pn => bn } 在这里,每一个习都是一个新的名字。如这里所示,这个匿名函数依次等价于下面的实例创建表达式,其中T是所有bi类型的弱最小上限。 新scala.FunctionkS1,…,Sk,T{应用(x1:s1,…),xk:Sk):t= (x1,…),xk)匹配{ case p1 => b1…案例pn => bn } 如果期望的类型是scala.PartialFunction[S, R],则将该表达式视为等效于以下实例创建表达式: 新scala.PartialFunctionS,T{ def应用(x: S):t=x match { case p1 => b1…情况pn => bn } def isDefinedAt(x: S):Boolean ={ case p1 => =>…情况pn => true case _ => false }

第一个代码片段是一个模式匹配的匿名函数,但不一定是一个部分函数。只有当它被赋予具有PartialFunction参数的方法或分配给类型为PartialFunction的变量时,它才会被转换为PartialFunction

因此,您是正确的,只有一些(模式匹配)匿名函数是部分函数(AFAIK,使用fat箭头(如x => x )定义的函数文本只能用于创建FunctionN实例,而不能用于创建PartialFunction实例)。

然而,并不是所有的部分函数都是匿名函数。定义PartialFunctions的一种无糖方法是扩展PartialFunction特性(扩展Function1)并手动重写isDefinedAtapply方法。例如,也可以使用匿名类定义divide2

代码语言:javascript
复制
val divide2 = new PartialFunction[Int, Int] {
  override def isDefinedAt(x: Int) = x != 0
  override def apply(x: Int) = 42 / x
}

但是,您可能不会经常看到这种情况,因为只使用模式匹配来定义PartialFunction要容易得多。

在Alexander链接的博客文章中,作者提到了将匿名部分函数文字匹配为匿名函数的模式,这仅仅是因为它既是一个部分函数,也是一个匿名函数。您还可以像这样定义函数:

代码语言:javascript
复制
List(42, "cat").collect(new PartialFunction[Any, Int] {
  def isDefinedAt(x: Any) = x.isInstanceOf[Int]
  def apply(x: Any) = x match {
    case i: Int => i + 1
  }
})

它不再是一个匿名函数,尽管它仍然是一个匿名对象--匿名类的实例。或者您可以预先定义一个单例对象,然后使用它。

代码语言:javascript
复制
object Foo extends PartialFunction[Any, Int] {
  def isDefinedAt(x: Any) = x.isInstanceOf[Int]
  def apply(x: Any) = x match {
    case i: Int => i + 1
  }
}
List(42, "cat").collect(Foo)

不管你怎么定义它,它都是一个部分函数。

票数 1
EN

Stack Overflow用户

发布于 2020-08-22 19:45:05

匿名和局部是不同的概念。我们不会说下面的函数是匿名的

代码语言:javascript
复制
val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}

因为它绑定到名称divide2,所以我们可以说divide2是用匿名(函数)值定义的。

代码语言:javascript
复制
{ case d: Int if d != 0 => 42 / d }

在同样的意义上,x定义为以下定义中的匿名值42

代码语言:javascript
复制
val x: Int = 42

部分的正交概念是指函数的特殊子类型,而不是特定类型的值是否绑定到名称。

票数 3
EN

Stack Overflow用户

发布于 2020-08-22 19:27:10

下面是另一种编写模式匹配部分函数的方法。

代码语言:javascript
复制
val divide = new PartialFunction[Int, Int] {
    def apply(x: Int) = 42 / x
    def isDefinedAt(x: Int) = x != 0
}

本质上,部分函数是没有为一组输入定义的函数。就像在这个例子中,用0除以0是没有意义的,或者您可以限制一些特定的值。

部分功能的巧妙之处在于它与orElse、andThen和collect具有协同作用。取决于您是否要在除法函数中输入0,如果变量不是0,则可以传递给andThen,如果是0,则可以通过orElse传递。最后,只有在对输入定义了部分函数时,collect才会应用它。

创建部分函数的方法通常是通过模式匹配和大小写进行匹配,如示例所示。

最后一点,Scala中的匿名函数就像Python中的lambda。这只是一种不用“命名”就可以创建函数的方法。

例如

代码语言:javascript
复制
val f: Int => Int = (x: Int) => x * x
collect {
    case a: Int => 1-a
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63540024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档