首页 文章

与实施特征上的@匹配模式?

提问于
浏览
1

鉴于:

sealed trait Request

sealed trait HasProxy extends Request
sealed trait HasFoo extends Request

case object One extends HasProxy with HasFoo
case object Two extends HasFoo
case object Three extends HasProxy with HasFoo
case object Four extends HasFoo
case object Five extends HasProxy

我定义了一个接受 HasFoo 类型的函数 .

def f(x: HasFoo) = ???

最后,我尝试编写一个函数,给定 Request ,将在 HasFoo 情况下进行模式匹配,即 OneTwoThreeFour .

scala> def foo(request: Request) = request match {
     |   case xxx @ (One | Two | Three | Four ) => f(xxx)
     | }
<console>:23: error: type mismatch;
 found   : Request
 required: HasFoo
         case xxx @ (One | Two | Three | Four ) => f(xxx)
                                                     ^

但是,上面的失败了 .

它们各自都有 HasFoo ,但我不确定它是如何适用于模式匹配的 .

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> lub ( List( typeOf[One.type], typeOf[Two.type],
     |             typeOf[Three.type], typeOf[Four.type] )
     | )
res2: reflect.runtime.universe.Type = HasFoo with Serializable with Product

而不是为 One ... Four 的每个模式匹配调用 f(_)

scala> def foo(request: Request) = request match {
     |  case One => ???
     |  case Two => ???
     |  ...
     |  case _   => ???
     | }
foo: (request: Request)Nothing

or 检查运行时类型,即 case xxx : One | Two | Three | Four

scala> def foo(request: Request) = request match {
     |  case (_: One.type | _: Two.type | _: Three.type | _: Four.type ) => ???
     | }

我有更好的选择吗?

2 回答

  • 1

    这可能是编译器类型推断中的一个错误或至少是一个不受欢迎的限制,但一般来说,如果编译器无法理解某些东西的实际类型是什么 - 而且在这里你可以确定 - 你可以直接转换为正确的类型:

    case xxx @ (One | Two | Three | Four ) => f(xxx.asInstanceOf[HasFoo])
    

    是的,如果它在将来被修改,它不够优雅且可能不安全,但你几乎可以通过评论完全解决这个问题 .

    如果你希望编译器确保强制转换,那么模式匹配并使用一个guard子句来拒绝任何你想要的东西,例如:

    case xxx: HasFoo 
         if (xxx match { case One | Two | Three | Four => true
                         case _ => false
         }) => f(xxx)
    
  • 4

    如果你想匹配 HasFoo 的任何东西,那么显而易见:

    def foo(request: Request) = request match {
      case xxx: HasFoo => f(xxx)
      case _ => ???
    }
    

    由于 OneTwoThreeFour 都扩展 HasFoo ,因此第一种情况将匹配所有四种类型;但不是 Five .

相关问题