如何使 scala 编译器查找使用错误参数的案例类



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

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

[历史] 它曾经是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被用作类型而不是案例类实例,这是可能的,因为它用于接受Any作为参数的函数。

由于你声明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

我假设!是 akka 演员的 tell 运算符。

它的签名是

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

因此,您实际上可以向其发送任何内容,在这种情况下,您正在发送类型断开连接。 这是使用 akka actor 的最大缺点之一,这就是为什么有一个新模块 akka 类型化,您可以在其中为参与者定义类型安全的行为。

您可能想知道,如果您要发送一个您不希望的对象,为什么这在运行时不会爆炸。原因是参与者的接收是一个 PartFunction[Any, Unit],它"丢弃"未为 PF 定义的消息。

问题不在于编译器,而在于接受Any作为参数的方法!

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

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

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

另一方面,如果我们查看相应的 Akka 类型化!方法

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

然后我们看到它被类型参数T参数化,编译器会捕获它。

相关内容

  • 没有找到相关文章

最新更新