为什么我必须通过新关键字?

时间:2019-06-15 13:36:50

标签: scala akka new-operator

我有以下代码:

val fsm = TestFSMRef(new SenderCollectorFsm)

不理解,为什么我必须将实例传递给TestFSMRef

让我们看看TestFSMRef的定义:

object TestFSMRef {

  def apply[S, D, T <: Actor: ClassTag](
      factory: => T)(implicit ev: T <:< FSM[S, D], system: ActorSystem): TestFSMRef[S, D, T] = {
    val impl = system.asInstanceOf[ActorSystemImpl]
    new TestFSMRef(impl, Props(factory), impl.guardian.asInstanceOf[InternalActorRef], TestActorRef.randomName)
  }  

TActorClassTag的子类型,但是如何知道T必须是对象呢?

2 个答案:

答案 0 :(得分:3)

Scala是一种面向对象的语言。与几乎所有面向对象的语言一样,您只能将对象作为参数传递。而且,像大多数语言一样,类型也不是对象。

因此,由于您只能传递对象,而类型不是对象,因此很显然,您只能传递实例。

或者,更准确地说:存在两个单独的Universe,即 types 的宇宙和 values 的宇宙。在值的宇宙中,我们有一些方法将值作为圆括号(或有时用大括号)中的参数。

在类型宇宙中,我们有类型构造函数,该构造函数将类型作为方括号中的参数。

两个Universe恰好在一个地方相遇,并且是依赖于路径的类型。

答案 1 :(得分:3)

如果SenderCollectorFsm被定义为像这样的常规类

class SenderCollectorFsm(...

然后我们必须使用new,但是如果它像这样定义为case类

case class SenderCollectorFsm(...

然后我们可以写TestFSMRef(SenderCollectorFsm)

但是,正如JörgW Mittag解释的那样,在两种情况下,我们都传递的是,而不是类型。尽管我可以看到TestFSMRef(SenderCollectorFsm)看起来像我们在传递类型一样,但是它只是传递案例类实例的简写。请参阅Why "case class" doesn't need "new" to create a new object

还要注意,T不是ClassTag的子类型,因为type parameter clause

T <: Actor : ClassTag

T

上的两个不同的类型约束组成
T <: Actor
T : ClassTag

其中T <: Actor确实指定TActor的子类型,但是T : ClassTag指定T必须具有隐式类型类ClassTag[T]在适用范围。注意类型约束<::之间的区别,其中前者是上限,而后者是上下文限制