首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >令人惊讶的PartialFunction文字

令人惊讶的PartialFunction文字
EN

Stack Overflow用户
提问于 2020-08-20 17:33:46
回答 2查看 75关注 0票数 1

我只是困惑于这样一个事实:当内部不是pf时,这个部分函数MatchError并没有与MatchError一起爆炸。

代码语言:javascript
复制
sealed trait Inner
case class InnerA(name: String) extends Inner
case class InnerB(name: String, value: Int) extends Inner
case class Input(id: String, inner: Inner)

case class Output(id: String, inner: InnerA)

  val pf: PartialFunction[Input, Output] = { input =>
    input.inner match {
      case innerA: InnerA =>
        val Input(id, _) = input
        Output(id, innerA)
    }
  }

相反,它是简单的未定义的,因此它通过。

代码语言:javascript
复制
    Seq(
      Input("1", InnerA("a1")),
      Input("2", InnerB("b2", 2)),
      Input("3", InnerA("a3"))
    ).collect(pf) shouldBe Seq(
      Output("1", InnerA("a1")),
      Output("3", InnerA("a3"))
    )

如果我添加一行,就会收到编译警告,并试图在上面的集合中传递一个InnerB,就会抛出一个MatchError (正如我最初预期的那样):

代码语言:javascript
复制
  val pf: PartialFunction[Input, Output] = { input =>
    println(input)
    input.inner match {
      case innerA: InnerA =>
        val Input(id, _) = input
        Output(id, innerA)
    }
  }
代码语言:javascript
复制
InnerB(b2,2) (of class casa.InnerB)
scala.MatchError: InnerB(b2,2) (of class casa.InnerB)

为什么会这样呢?这个怪癖在什么地方被记录下来了吗?

(我使用Scala2.13.3)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-21 07:33:37

当内部不是MatchError时,这个部分函数pf不会与InnerA一起爆炸

如果你直接用这样的论点来称呼它

代码语言:javascript
复制
pf(Input("a", InnerB("b", 0)))

您确实得到了一个MatchError;但是PartialFunction的全部意义是在isDefinedAt中提供其他信息,而collect使用它时不调用isDefinedAt返回falsepf

这个怪癖在什么地方被记录下来了吗?

见规范的6.23.1翻译段:

当需要一个PartialFunction时,会合成一个额外的成员isDefinedAt,它只是返回true。但是,如果函数文字具有形状x => x match { … },那么isDefinedAt是从模式匹配派生出来的,其方式如下:匹配表达式中的每个大小写计算结果为true,如果没有默认大小写,则添加一个默认大小写,其计算结果为false

因此,对于您的第二个版本,isDefinedAt总是true;第一个版本并不完全适合x => x match...,但显然它也是受支持的。现在,通常定义PartialFunction的方法就像Luisía Suárez的评论那样

代码语言:javascript
复制
{ case Input(id, InnerA(name)) => Output(id, InnerA(name)) }

但它只是简单地被翻译成

代码语言:javascript
复制
x => x match { case Input(id, InnerA(name)) => Output(id, InnerA(name)) }
票数 2
EN

Stack Overflow用户

发布于 2020-08-20 22:10:47

正在发生的情况是,在第一种情况下,编译器正在“删除”input匹配并使用input.inner

当我运行scalac -Xprint:typer Test.scala时,第一段代码变成:

代码语言:javascript
复制
final override def applyOrElse[A1 <: Input, B1 >: Output](input: A1, default: A1 => B1): B1 = (input.inner: Inner @unchecked) match {
  case (innerA @ (_: InnerA)) => {
    val id: String = (input: A1 @unchecked) match {
      case (id: String, inner: Inner): Input((id @ _), _) => id
    };
    Output.apply(id, innerA)
  }
  case (defaultCase$ @ _) => default.apply(input)
};

final def isDefinedAt(input: Input): Boolean = (input.inner: Inner @unchecked) match {
  case (innerA @ (_: InnerA)) => true
  case (defaultCase$ @ _) => false
}

这意味着您的函数的行为将像PartialFunction[Inner, Output],因此编译器知道它不需要警告您,您的匹配不是详尽无遗的。

另一方面,当您看到带有print指令的方法的结果时,您会得到:

代码语言:javascript
复制
final override def applyOrElse[A1 <: Input, B1 >: Output](input: A1, default: A1 => B1): B1 = ((input.asInstanceOf[Input]: Input): Input @unchecked) match {
  case (defaultCase$ @ _) => {
    scala.Predef.println("xxx");
    input.inner match {
      case (innerA @ (_: InnerA)) => {
        val id: String = (input: A1 @unchecked) match {
          case (id: String, inner: Inner): Input((id @ _), _) => id
        };
        Output.apply(id, innerA)
      }
    }
  }
  case (defaultCase$ @ _) => default.apply(input)
};
final def isDefinedAt(input: Input): Boolean = ((input.asInstanceOf[Input]: Input): Input @unchecked) match {
  case (defaultCase$ @ _) => true
  case (defaultCase$ @ _) => false
}

在本例中,您将创建一个为所有输入间隔定义的PartialFunction[Input, Output],这是很好的。但是,当编译器检查内部input.inner match时,它警告您,这个匹配(不是第一个匹配)并不是详尽无遗的。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63510390

复制
相关文章

相似问题

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