无法访问特质实施的其他方法

时间:2019-11-28 20:32:07

标签: scala

请查看以下示例:

trait MyTrait {
  def myTraitMeth : String
}

object TraitImplementation extends MyTrait {
  def myTraitMeth = "Works fine"
  def myExtraMeth = "Doesn't work"
}
case object Manager {
  def returnImplementation : MyTrait = TraitImplementation
}

println(Manager.returnImplementation.myExtraMeth)

在这种情况下,发生的事情是我无法访问特质实现TraitImplementation的额外方法,因为我将方法returnImplementation的返回方法定义为类型MyTrait-我无法更改此条件。

一个明显的解决方案是在trait上强制使用这种额外的方法,但是考虑到MyTrait的其他实现不能拥有这样的方法,这对我来说不是一个选择。

我真正需要的是确保方法returnImplementation返回的是MyTrait的实现,并同时允许该方法的调用者使用所有方法已经实施的,不仅是在特质上实施的。

我尝试弄乱类型,使用

case object Manager {
  def returnImplementation [A <: MyTrait] : A = TraitImplementation
}

但这会导致类型不匹配,因为编译器无法理解A是泛型类型。

关于如何实现它的任何想法?

1 个答案:

答案 0 :(得分:0)

我本来想发表评论,但由于正在进行讨论,所以空间变得有些拥挤。我决定将其写为答案。

您遇到的这个问题听起来像可以通过使用大小写匹配来解决。当returnImplementation返回一个MyTrait类型的特征时,对其进行大小写匹配以获取所需的子类,并且取决于它是哪个子类,它们具有不同的行为。如果您想要单子快速失败行为,请将其包装在Option中,以便仅某些子类将触发某些结果的创建。如果找到具有所需方法的所需子类,则结果为Some(...),否则为None。

trait MyTrait {
  def myTraitMeth : String
}

object TraitImplementation extends MyTrait {
  def myTraitMeth = "Works fine"
  def myExtraMeth = "Doesn't work"
}
case object Manager {
  def returnImplementation : MyTrait = TraitImplementation
}

对于您的println语句,您可以这样称呼它:

Manager.returnImplementation match {
  case TraitImplementation => println(TraitImplementation.myExtraMeth)
  case _ =>
}

如果您想保持代码的纯功能性而没有诸如println函数之类的副作用,请执行以下操作:

val result = Manager.returnImplementation match {
  case TraitImplementation => Some(TraitImplementation)
  case _ => None
}

result的类型为Option [TraitImplementation],您可以将其传递给上下文相关行为。

如果您有副作用代码(例如println语句),则可以通过在此Option上调用foreach来将其与其余纯函数代码隔离开来,如下所示:

result.foreach(x => println(x.myExtraMeth))

根据您和Luis的讨论,您还可以在MyExtTrait上进行大小写匹配,以实现所需的行为。

trait MyExtTrait {
  def myExtraMeth: String
}

val result = Manager.returnImplementation match {
  case x: MyExtTrait => println(x.myExtraMeth)
  case _ => 
}

val result = Manager.returnImplementation match {
  case x: MyExtTrait => Some(x)
  case _ =>  None
}

result.foreach(x => println(x.myExtraMeth))