我有一个接收函数的方法,但是该函数可能是部分函数,在这种情况下,我不希望它因MatchError而失败。
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p:PartialFunction[X,Y]=> opt.flatMap(p.lift) //This doesn't seem to work
case _ => opt.map(f)
}
}
这样我就可以使用这样的方法
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
所以如果我没有谓词,我可以像这样使用它
此doSomething(x)(otherMethod)
而不是
doSoemthing(x){
case t=> otherMethod(t)
}
注意:寻找不需要捕获MatchError
异常的解决方案
答案 0 :(得分:2)
这不是答案,因为我认为您想要的东西在Scala中是不可能的。
原始方法很好,并且可以按预期工作,尽管可能会更简单:
def doSomething[X, Y](opt: Option[X])(f: X => Y): Option[Y] = {
f match {
case p: PartialFunction[X, Y] => opt.collect(p)
case _ => opt.map(f)
}
}
问题在这里:
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
Scala正在根据该Function
表达式创建一个PartialFunction
而不是一个match
,因此测试失败。如果您通过真实的PartialFunction
,则该方法正常。
val p: PartialFunction[Int, Int] = {
case i: Int if i > 0 => i
}
doSomething(Some(0))(p) // Returns None
我认为没有任何方法可以做您想要的事情,主要是因为doSomething
有多个参数列表,这些参数列表混淆了第二个参数列表的类型推导。
我的建议只是使用
x.map(f)
或
x.collect{
case ...
}
在调用代码中适当。
答案 1 :(得分:1)
从SLS 8.5的2.9开始,已更改了部分函数的语法,因此即使您执行{ case x => y}
,也并不意味着它是部分函数。其类型将与您定义的完全相同。
在您的情况下,您将其定义为X=>Y
(如在函数参数中一样),因此它只是一个X=>Y
(已编译为常规函数,非匹配用例将引发MatchError ),甚至您isInstanceOf[PartialFunciton[_,_]]
也不会匹配。
要使您的方案起作用,您只需将传递的函数转换为PartialFunction即可,例如:
doSomething(Some(1))({case 2 => 0}: PartialFunction[Int,Int]) //This returns None without MatchError
同时
doSomething(Some(1)){case 2 => 0} //This gives MatchError and it is not recognized as PartialFunction inside the body
这可能不如您想像的那样方便,但这是使其工作的唯一方法。 (或者您针对这两种情况分别定义2个单独的函数,例如标准库中的collect
和map
)
答案 2 :(得分:-2)
我不确定您要作为部分函数传递什么,但绝对必须使用如下特定签名来定义它:
val positive: PartialFunction[Int, Option[Int]] = {
case x if x >= 0 => Some(x)
case _ => None
positive
函数仅用于正数。如果为负数,该函数将返回None,并且在运行时不会出现scala.MatchError。
此特定功能使您可以访问isDefinedAt
方法,该方法将动态测试值是否在函数的域中。
postive(5).isDefinedAt //是
poistive.isInstanceOf [PartialFunction [Int,Option [Int]]] // true
我在这里说明了为什么您在检查p.isInstanceOf
时总是假
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p if p.isInstanceOf[PartialFunction[X,Y]] =>
println("I'm a pf")
println(s"Is it PartialFunction: ${p.isInstanceOf[PartialFunction[X,Y]]}")
opt.map(p)
case _ =>
println("I'm not a pf")
opt.map(f)
}
}
doSomething[Int, Option[Int]](Some(5))(positive) // partial function case
doSomething[Int, String](Some(5)) { // tricky case
case s => s.toString
}
您可以here:使用它