簡體   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