在Scala中,是否有更好的方法提升PartialFunction?

6

我偶尔会遇到以下模式,本质上我有一个PartialFunction[SomeType,AnotherType],并希望将其视为Function[SomeType,Option[AnotherType]],例如:

def f(s:SomeType):Option[AnotherType] = s match {
  case s1:SubType1 => Some(AnotherType(s1.whatever))
  case s2:SubType2 => Some(AnotherType(s2.whatever))
  case _ => None
}

有没有一种方法可以避免默认情况并在定义时不用Some包装结果来编写上述函数?到目前为止,我想到的最好方法是这样的:
def f(s:SomeType):Option[AnotherType] = pf.lift(s)
def pf:PartialFunction[SomeType,AnotherType] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}

有没有不需要定义中间函数的方法?我已经尝试了各种类似以下代码的方法,但是还没有编译成功:

def f:Function[SomeType,Option[AnotherType]] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}.lift

中间函数是什么意思? - Raphael
@Raphael 函数字面量不是部分函数字面量,除非有类型提示表明它是部分函数字面量。 - Daniel C. Sobral
啊,“我有”意思是“我写代码”,不是“我有一个类型的值”。误解了,抱歉。 - Raphael
2个回答

8

condOpt是scala.PartialFunction对象中的一个方法。来自scaladoc:

def onlyInt(v: Any): Option[Int] = condOpt(v) { case x: Int => x }

但是 condOpt(x)(pf) 等同于 pf.lift(x)。我有什么遗漏吗?还是说重点在于你可以在这里使用函数字面量而不需要显式类型注释? - oxbow_lakes
@oxbow_lakes,我不能代表Kristian发言,也没有太多考虑这个问题或我的回答,“condOpt”只是似乎与他所问的相关。 - huynhjl
事实上,我喜欢condOpt能够推断类型的特性。 - Kristian Domagala

4

这不是一个答案,而是解释为什么huynhjl的回答是正确的...

你的困惑部分在于你试图定义一个偏函数。这只会创建一个返回PartialFunction对象的方法,而你可以直接创建它:

val pf: PartialFunction[SomeType,AnotherType] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}

虽然我个人更喜欢使用类型标注:

val pf = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
} : PartialFunction[SomeType,AnotherType]

无论哪种方式,您都必须指定输入类型,因此必须给出PartialFunction的确切签名。我知道这感觉应该是可以推断的,但遗憾的是,情况并非如此!使用指定版本,您可以在同一位置定义和提取:
val pf = ({
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
} : PartialFunction[SomeType,AnotherType]).lift

PartialFunction.condOpt 是更好的解决方案,因为它允许推断器为您完成大部分工作,从而使代码更加简洁 :)


这正是我需要相同行为时所做的事情:很遗憾condOpt是一个糟糕的方法名。我会使用applyLifted代替它。我不知道为什么他们没有这样命名! - oxbow_lakes
这并不是世界上最直观的名称,不是吗? - Kevin Wright
谢谢Kevin,我想我也尝试过val,但可能是错误的咒语。你的答案肯定是我要走的路线,但我接受了huynhjl的答案,因为它更符合我的需求(尽管函数名不同!) - Kristian Domagala
@Kristian 很正确,我的回答只是为了澄清为什么那是正确的答案。 - Kevin Wright

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接