Scala Trait类型不匹配

时间:2017-09-25 17:27:44

标签: scala scala-generics

我在项目中使用了一些Kafka Channel层次结构:

我的基本特征是:

function Selector($injector) {
        var vm = this;
        vm.constant  = $injector.get(constantProvider);    
    }

<selector
  constant-provider="SOME_OTHER_CONSTANTS"
  form="vm.myForm"
  model="vm.myModel>
</selector>

现在我有一个常见的kafka发送频道,如

module.factory('MyConstants', function(CONSTANTS, SOME_OTHER_CONSTANTS) {
  return {
    name1: CONSTANTS, name2: SOME_OTHER_CONSTANTS
  }
});

现在CommanKafkaSendChannel有2个变体,一个是回调,一个是Future:

trait SendChannel[A, B] extends CommunicationChannel {
  def send(data:A): B
}

trait CommonKafkaSendChannel[A, B, Return] extends SendChannel[A, Return] { val channelProps: KafkaSendChannelProperties val kafkaProducer: Producer[String, B] override def close(): Unit = kafkaProducer.close() } 定义:

trait KafkaSendChannelWithFuture[A, B] extends CommonKafkaSendChannel[A, B, Future[RecordMetadata]] {
override def send(data: A): Future[RecordMetadata] = Future {
  kafkaProducer.send(new ProducerRecord[String, B](channelProps.topic)).get
}
}

现在根据配置值,我在运行时选择合适的通道类型,如下所示。我正在创建具有正确类型的通道的actor,它将数据发送到kafka:

KafkaSendChannelWithCallback

演员定义:

object KafkaSendChannelWithCallback {

def apply[A, B](oChannelProps: KafkaSendChannelProperties,
              oKafkaProducer: Producer[String, B],
              oCallback: Callback): KafkaSendChannelWithCallback[A, B] =
new KafkaSendChannelWithCallback[A,B] {
  override val channelProps: KafkaSendChannelProperties = oChannelProps
  override val kafkaProducer: Producer[String, B] = oKafkaProducer
  override val callback: Callback = oCallback
}
}

trait KafkaSendChannelWithCallback[A, B] extends CommonKafkaSendChannel[A, B, Unit] {

  val callback: Callback

override def send(data: A): Unit =
kafkaProducer.send(new ProducerRecord[String, B](channelProps.topic), callback)
}

问题是,当我使用 val sendChannel = kafkaChannel.channel(config, actorSystem).fold( error => { logger.error("Exception while instantiating the KafkaSendChannel") throw error }, success => success ) actor = actorSystem.actorOf(IngestionActor.props(config, sendChannel), name = ACTOR_NAME) 时,我的代码会正确编译,但是当我使用object IngestionRouterActor { def props[V](config: Config, sendChannel: SendChannel[V, Unit]): Props = Props(classOf[IngestionActor[V]], config, sendChannel) } 时,它会在KafkaSendChannelWithCallback声明中给出以下错误:

  

[error] IngestionActor.scala:32:模式类型与预期类型不兼容;   [错误]发现:KafkaSendChannelWithFuture [String,V]   [error] required:SendChannel [V,Unit]

由于两个通道定义都是从KafkaSendChannelWithFuture扩展而来的,因此该代码应该编译时没有任何错误。我不确定为什么它不编译。感谢

1 个答案:

答案 0 :(得分:1)

Props的{​​{1}}需要IngestionActor。传入SendChannel[V, Unit]到这个参数是有效的,因为它是KafkaSendChannelWithCallback

另一方面,SendChannel[V, Unit]KafkaSendChannelWithFutureSendChannel[V, Future[RecordMetadata]] SendChannel[V, Future[RecordMetadata]]

一种选择是重新定义SendChannel[V, Unit]以获取Props,因为SendChannel[V, Any]AnyUnit的超类型:

Future

此时,编译器仍然不满意,因为作为泛型类型的def props[V](config: Config, sendChannel: SendChannel[V, Any]): Props = ??? 默认情况下是不变的。换句话说,SendChannelSendChannel[V, Unit]都不属于SendChannel[V, Future[RecordMetadata]]类型。

要更改此设置,请在第二个类型参数上设置SendChannel[V, Any]协变(通过在SendChannel前添加+):

B