我有一个其中带有1个参数的case class Disconnect(nodeId: PublicKey)
,但是在代码的其他部分,它恰好是在没有参数的情况下使用的,即:Disconnect
并且编译器没有捕获到错误,请注意,我还尝试使用-Xlint
选项运行编译器,但仍然无法捕获错误。
-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}}作为参数。
答案 0 :(得分:2)
由于您将Disconnect
声明为case class
,因此编译器会自动生成一个伴随object Disconnect
,其中包含所有简洁的apply
和unapply
方法。因此,Peer.Disconnect
是单例类型Peer.Disconnect.type
的完全有效的表达式。有人可能会说,如果您从一开始就使用Akka Typed,就不会发生这种情况,但是在您的代码中,!
方法可以接受任何内容,因此为了强制编译器发出一些有意义的错误消息,您可以还需要其他东西。这是一种简单的方法:
Disconnect
是单例对象而没有关联的案例类的状态。Disconnect
定义。添加case class NewDisconnect
。现在,Peer.Disconnect
的每次出现都会成为正确的错误。Peer.Disconnect
替换为Peer.NewDisconnect(foo)
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定义的消息。