如何使Scala编译器查找带有错误参数的案例类

时间:2019-06-26 12:54:06

标签: scala maven scalac

我有一个其中带有1个参数的case class Disconnect(nodeId: PublicKey),但是在代码的其他部分,它恰好是在没有参数的情况下使用的,即:Disconnect并且编译器没有捕获到错误,请注意,我还尝试使用-Xlint选项运行编译器,但仍然无法捕获错误。

  • scala版本:2.11.12
  • 目标jvm版本:1.8
  • 使用选项编译的代码: -deprecation -feature -language:postfixOps -language:implicitConversions -Xfatal-warnings -unchecked -Xmax-classfile-name 140 -nobootcp

[history]以前是case object Disconnect,但在某些时候它已更改为case类并添加了一个参数,在代码中它仍然被实例化为无参数,并且编译器无法注意到它。我尝试将-Xlint选项添加到编译器中,但没有帮助。

在Peer.scala中

  object Peer { 
    // other code
    case class Disconnect(nodeId: PublicKey)
    // more code
  }  

在Channel.scala中

  // inside a function
  revocationTimeout.peer ! Peer.Disconnect
  //

我希望编译器能够抓住case类的滥用而无法编译。

编辑:感谢所有答复,确实编译器做得很好,并且Disconnect被用作类型而不是case类实例,这是可能的,因为它被用于接受{ {1}}作为参数。

3 个答案:

答案 0 :(得分:2)

由于您将Disconnect声明为case class,因此编译器会自动生成一个伴随object Disconnect,其中包含所有简洁的applyunapply方法。因此,Peer.Disconnect是单例类型Peer.Disconnect.type的完全有效的表达式。有人可能会说,如果您从一开始就使用Akka Typed,就不会发生这种情况,但是在您的代码中,!方法可以接受任何内容,因此为了强制编译器发出一些有意义的错误消息,您可以还需要其他东西。这是一种简单的方法:

  1. 返回到Disconnect是单例对象而没有关联的案例类的状态。
  2. 完全删除Disconnect定义。添加case class NewDisconnect。现在,Peer.Disconnect的每次出现都会成为正确的错误
  3. 将所有Peer.Disconnect替换为Peer.NewDisconnect(foo)
  4. NewDisconnect重命名为Disconnect

答案 1 :(得分:1)

问题不在编译器中,而在方法!中,该方法接受Any作为参数:

def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit

因此我们可以将参数更改为任何参数,并且仍然可以编译,例如

revocationTimeout.peer ! "woohoo"  // compiles OK!

另一方面,如果我们看一下对应的Akka Typed !方法

implicit final class ActorRefOps[-T](val ref: ActorRef[T]) extends AnyVal {
    def !(msg: T): Unit = ref.tell(msg)
}

然后我们看到它是用类型参数T进行参数化的,编译器会捕获它。

答案 2 :(得分:1)

我假设!是来自akka演员的告诉操作员。

它的签名是

def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit

因此,您可以发送任何内容,在这种情况下,您将发送“断开连接”类型。 这是使用akka actor的最大缺点之一,这就是为什么有一个新模块akka typed可以为actor定义类型安全行为的原因。

您可能想知道,如果发送的对象不是您所期望的,为什么它在运行时不会消失。原因是参与者的接收是PartialFunction [Any,Unit],它“丢弃”未为PF定义的消息。