繁体   English   中英

为什么我的验证在检查输入类型时不抛出异常?

[英]Why doesn't my validation throw exception when it checks for the input type?

我的方法:

protected final def validatePayload[T](payload: Option[Payload]) = {
    payload match {
      case None => throw new IllegalArgumentException("Payload was None.")
      case Some(p) => p.resource match {
        case None => throw new IllegalArgumentException("Resource was None.")
        case Some(resource) => resource match {
          case temp: T =>
          case _ => throw new IllegalArgumentException("Resource is not the right type.")
        }
      }
    }
  }

有效负载:

case class Payload(id: String, resource: Option[Any])

用法:

  validatePayload[String](Some(Payload("id", Some(5))))

我希望这会抛出非法的arg,因为我要告诉它接受String并传递一个Int值。 为什么不呢?

我的目标是验证已将有效负载发送给参与者,参与者仅应对特定类型的资源做出反应,而别无其他。 我该如何解决这个问题?

类标签

最简单的情况是可以使用ClassTag的情况(下面给出了这种情况的限制)。 在这种情况下,您只需添加绑定到函数类型定义的上下文,它就可以工作:

import scala.reflect.ClassTag

protected final def validatePayload[T : ClassTag](payload: Option[Payload]) = {
  // everything else is the same...
}

// Throws an error
validatePayload[String](Some(Payload("id", Some(5)))) 

在运行时,它几乎等效于Java的instanceof运算符和类型强制转换。

类型标签

但是ClassTag不适用于泛型类型。 例如,不区分具有不同元素类型的序列:

// Doesn't throw
validatePayload[Seq[String]](Some(Payload("id", Some(Seq(1,2,3)))))

如果需要区分泛型类型,则必须使用TypeTag 创建有效负载时, 必须知道资源的类型,并且有效负载必须存储其Type或该TypeTypeTag

这是一个例子:

import reflect.runtime.universe._

case class Payload[T](id: String, resource: Option[T])(implicit val tag: TypeTag[T])

def validatePayload[T : TypeTag](payload: Option[Payload[_]]) = {
  payload match {
    case None => throw new IllegalArgumentException("Payload was None.")
    case Some(p) => p.resource match {
      case None => throw new IllegalArgumentException("Resource was None.")
      case Some(resource) => resource match {
        case temp if p.tag.tpe <:< typeOf[T] =>
        case _ => throw new IllegalArgumentException("Resource is not the right type.")
      }
    }
  }
}

现在它将区分泛型:

// Throws an error
validatePayload[Seq[String]](Some(Payload("id", Some(Seq(1,2,3)))))

但是TypeTag依赖于编译时已知的类型。 因此,如果在使用resource创建Payload之前resource类型为Any ,则仅当TAny validatePayload[T]不会抛出。 还有其他一些怪癖:

// Doesn't throw
validatePayload[Seq[Int]](Some(Payload("id", Some(List(1,2,3)))))
// Throws, although resource *is* a List[Int] at runtime
validatePayload[List[Int]](Some(Payload("id", Some(Seq(1,2,3)))))

从无形铸造

第三方库shapeless提供了更强大的方法。 这是一个例子:

import shapeless.Typeable
import shapeless.syntax.typeable._

def validatePayload[T : Typeable](payload: Option[Payload]) = {
  payload match {
    case None => throw new IllegalArgumentException("Payload was None.")
    case Some(p) => p.resource match {
      case None => throw new IllegalArgumentException("Resource was None.")
      case Some(resource) => resource match {
        case temp if temp.cast[T].isDefined =>
        case _ => throw new IllegalArgumentException("Resource is not the right type.")
      }
    }
  }
}

两者都不抛出:

validatePayload[Seq[Int]](Some(Payload("id", Some(List(1,2,3)))))
validatePayload[List[Int]](Some(Payload("id", Some(Seq(1,2,3)))))

由于类型删除,您无法检查这种类型,但是ClassTag是一种解决方法。

case class Payload(id: String, resource: Option[Any])

import scala.reflect.ClassTag
def validatePayload[T: ClassTag](payload: Option[Payload]) = {
  payload flatMap (_.resource) filter { res =>
    val c = implicitly[ClassTag[T]].runtimeClass
    c.isInstance(res)
  } getOrElse (throw new IllegalArgumentException("Invalid payload"))
}

我简化了代码,如果您不需要自定义错误,至少对我来说,它不会那么冗长。 尽管如果您要坚持使用代码,那么从问题角度来看,只有重要的部分才声明类型T需要和隐式ClassTag[T] ,该声明像这样[T: ClassTag]并在此处检查类型是否有效:

val c = implicitly[ClassTag[T]].runtimeClass
c.isInstance(res)

这是一个测试

scala> validatePayload[String](Some(Payload("id", Some("a"))))
res3: Any = a

scala> validatePayload[String](Some(Payload("id", Some(5))))
java.lang.IllegalArgumentException: Invalid payload
  at $anonfun$validatePayload$3.apply(<console>:20)
  at $anonfun$validatePayload$3.apply(<console>:20)
  at scala.Option.getOrElse(Option.scala:121)
  at .validatePayload(<console>:20)
  ... 33 elided

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM