1

问题

在我之前的一个问题中,我提供了一个具有以下模式匹配的示例

class A

class B

sealed trait Test {
  type Meta
}

case class Test1() extends Test {
  type Meta = A
}
case class Test2() extends Test {
  type Meta = B
}

case class Info[T <: Test](t: T, m: T#Meta)

val t: Info[_ <: Test] = ???
t match {
  case Info(t: Test1, a: Test1#Meta) =>
    println("1")
  case Info(t: Test2, a: Test2#Meta) =>
    println("2")
}

此代码编译时出现以下警告:

match may not be exhaustive.
It would fail on the following inputs: 
Info((x: _$2 forSome x not in (Test1, Test2)), (x: _$2#Meta forSome x not in (A, B))), 
Info((x: _$2 forSome x not in (Test1, Test2)), ??), Info((x: _$2 forSome x not in (Test1, Test2)), A()), 
Info((x: _$2 forSome x not in (Test1, Test2)), B()), Info(??, (x: _$2#Meta forSome x not in (A, B))), 
Info(Test1(), (x: _$2#Meta forSome x not in (A, B))), 
Info(Test1(), B()), Info(Test2(), (x: _$2#Meta forSome x not in (A, B))),   
Info(Test2(), A())

正如Oleg Pyzhcov他们的回答中大大解释的那样,确实有可能构造一个无法匹配的值。

我的解决方案

所以我目前想到的解决办法就是用一个简单的宏来禁止这样的对象创建。这里是:

object Info {
  def apply[T <: Test](t: T, m: T#Meta): Info[T] = macro applyImpl[T]

  def applyImpl[T <: Test](c: blackbox.Context)(t: c.Expr[T], m: c.Expr[T#Meta]): c.Expr[Info[T]] = {
    import c.universe._


    val sourceType = weakTypeTag[T].tpe
    if (!sourceType.typeSymbol.isClass || !sourceType.typeSymbol.isFinal) {
      c.abort(
        c.enclosingPosition,
        s"Creating is allowed for specific types only"
      )
    }

    //... create an object
  }
}

有了这样apply的实现,就不可能再构造这样的对象了。

问题:在使用这种apply实现时抑制编译器发出的警告是否可靠?

4

0 回答 0