是否可以在没有警告的情况下在演员内部接收元组 "eliminated by erasure"

Is it possible to receive a tuple inside an actor without the warning "eliminated by erasure"

我想知道是否可以在 actor 内部接收元组,而不会收到此警告:

non-variable type argument Long in type pattern (Long, Int) is unchecked since it is eliminated by erasure

尽管代码似乎有效且有效:

override def receive: Receive = {
  case tuple: (Long, DateTime) => sendPlace(tuple._1, tuple._2)
}

我是不是漏掉了什么?

元组是通用类型,例如Tuple2[T1, T2] 并且在 JVM 中,这些类型参数被擦除并且不存在于运行时中。网上有很多关于这个话题的。

您的代码有效,但唯一检查消息是否与模式匹配的是消息是否为 Tuple2,而不是其内部类型。如果这个 actor 得到另一个 Tuple2,比如 (String, String),当你尝试将 String 转换为 Long 时,你将得到一个 class 转换异常,当你试图传递第一个元素时sendPlace 方法。

例如在下面

override def receive: Receive = {
  case tuple: (Long, DateTime) => sendPlace(tuple._1, tuple._2)
  case tuple: (Int, Int) => sender ! (tuple._1 + tuple._2)
}

第二个模式无法访问,它永远不会匹配,因为任何 Tuple2 将匹配第一个模式并在类型错误时抛出异常。

一般来说,您应该为消息创建大小写 classes。这对消息及其成员都有一个有意义的名称的好处,元组仅说明其类型。您应该在其伴随对象中定义 actor 可以处理的消息。

object BookingActor {
  case class BookingRequest(placeId: Long, bookingTime: DateTime)
}

class BookingActor {
  import BookingActor._

  override def receive: Receive = {
    case BookingRequest(id, time) => bookPlace(id, time)
  }

  // ...
}

写作

case (id: Long, time: DateTime) => sendPlace(id, time)

也会避免未经检查的转换,但 Łukasz 是对的:您应该为此目的定义一个案例 class。

since two applications are communicating together it allows me not to define two times the case class

当然你不应该定义它两次。在两个应用程序都依赖的库中定义一次。这样 1) 您可以明确应用程序通信的位置; 2) 如果您需要更改消息类型(例如添加另一个字段,或更改其中一个字段的类型),您将不太可能忘记更改其中一侧。

Can you just, please, explain why I don't get this warning when it is not in the context of an actor that receives a message?

你做到了:

val x: Any = ("a", "b")

x match {
  case tuple: (Long, DateTime) => 
    println("shouldn't match, but does")
}