Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 在多个级别扩展traits时不可变返回类型的继承_Scala_Traits - Fatal编程技术网

Scala 在多个级别扩展traits时不可变返回类型的继承

Scala 在多个级别扩展traits时不可变返回类型的继承,scala,traits,Scala,Traits,我有以下特征层次结构。TraitA是根特征,如果我希望我的数据结构是不可变的,那么commonUpdateFunction函数有一个通用的返回类型。我不确定这是不是最好的办法。我还有两个扩展它的特性,添加了另外两个函数。有些类扩展一个类,有些类扩展另一个类,但有些类需要同时扩展这两个类 然而,我现在遇到了一个问题,由于泛型类型的原因,我获得了非法继承,而实际上,我这样做只是为了在将数据结构更新为新结构时获得正确的类型 此外,由于这个泛型类型,我似乎无法将TraitA作为参数传递 trait Tr

我有以下特征层次结构。TraitA是根特征,如果我希望我的数据结构是不可变的,那么commonUpdateFunction函数有一个通用的返回类型。我不确定这是不是最好的办法。我还有两个扩展它的特性,添加了另外两个函数。有些类扩展一个类,有些类扩展另一个类,但有些类需要同时扩展这两个类

然而,我现在遇到了一个问题,由于泛型类型的原因,我获得了非法继承,而实际上,我这样做只是为了在将数据结构更新为新结构时获得正确的类型

此外,由于这个泛型类型,我似乎无法将TraitA作为参数传递

trait TraitA[T <: TraitA[T]]
{
   self : T =>

   def commonUpdateFunction() : T
}

trait TraitB extends TraitA[TraitB]
{
   def someFunctionB() : Integer = { /// some code }
}

trait TraitC extends TraitA[TraitC]
{
   def someFunctionC() : Unit = { /// some code } 
}

class ClassB extends TraitB 
{
   def commonUpdateFunction() : ClassB = { /// some code } 
}

class ClassC extends TraitC
{
   def commonUpdateFunction() : ClassC = { /// some code }
} 

class ClassA extends TraitB with TraitC  //**this causes illegal inheritance**
{
   def commonUpdateFunction() : ClassA = { /// some code }
} 

在使用正确的类型对数据结构进行不可变的更新的同时,实现对2个特征的继承的正确方法是什么

这里类型参数不是您的问题,问题是ClassA试图混入commonFunction的三个副本,它们只在返回类型上有所不同:

class ClassA extends TraitB with TraitC {
  def commonFunction() : ClassA = { /// some code }
  def commonFunction() : ClassB = { /// some code } 
  def commonFunction() : ClassC = { /// some code } 
} 
尽管JVM确实允许在返回类型上重载,但在编译时是不允许的——特别是在涉及类型推断的情况下,混淆的可能性太大了

解决方案通常是使用f-有界多态性,就像您在commonUpdateFunction中所做的那样,但鉴于您所有的commonFunction定义都是具体的,因此不可能在这里说明如何做到这一点

看到更多真实的代码会有很大帮助

更新:基于评论中的新信息

您可能会发现使用抽象类型成员比使用类型参数更容易。使用Repr表示是一种常见的约定,在集合库中使用;确保此抽象类型成员具有绑定

将其他常见属性也粘贴在此处:

trait Employee {
  type Repr <: Employee

  def name : String
  def id   : Int

  def withName(name: String) : Repr
  def withId(id: Int) : Repr
}

类型参数在这里不是您的问题,问题是ClassA试图混入commonFunction的三个副本,它们只在返回类型上有所不同:

class ClassA extends TraitB with TraitC {
  def commonFunction() : ClassA = { /// some code }
  def commonFunction() : ClassB = { /// some code } 
  def commonFunction() : ClassC = { /// some code } 
} 
尽管JVM确实允许在返回类型上重载,但在编译时是不允许的——特别是在涉及类型推断的情况下,混淆的可能性太大了

解决方案通常是使用f-有界多态性,就像您在commonUpdateFunction中所做的那样,但鉴于您所有的commonFunction定义都是具体的,因此不可能在这里说明如何做到这一点

看到更多真实的代码会有很大帮助

更新:基于评论中的新信息

您可能会发现使用抽象类型成员比使用类型参数更容易。使用Repr表示是一种常见的约定,在集合库中使用;确保此抽象类型成员具有绑定

将其他常见属性也粘贴在此处:

trait Employee {
  type Repr <: Employee

  def name : String
  def id   : Int

  def withName(name: String) : Repr
  def withId(id: Int) : Repr
}

我是Scala的初学者,所以我可能遗漏了一些重要的设计原则。我正在努力弄清楚的是,如何在保持数据对象不变的同时实现传统的OO多态性。这将是一个典型的例子:Employee作为一个抽象类,它有名称和employeeId,还有一些类扩展它,比如Technician和Manager。更新名称或employeeId的方法必须创建另一个相同类型的实例(如果它是不可变的)。另一方面,系统的其余部分有一些方法,这些方法可以接受employees。在这种情况下,您可以将Employee作为trait,并为technology和Manager创建case类子类型。像对commonUpdateFunction那样声明withName和withId,然后根据copy方法在case类中定义。我想知道您是否希望commonFunction和commonUpdateFunction在您的示例中是相同的东西;因为现在他们非常不同,我错了,他们应该是一样的。固定的是的,我明白了,问题出现在其他地方,我只需要使用Employee作为一个完全无关类的方法的参数。它不在乎自己是什么类型的员工。现在我只是得到了一些错误,说它需要指定类型,我想是因为[T]的东西,它是用来确定不可变类的真正类型的。所以您声明了一个内部类型,它被具体类重写。。。好把戏!我会尝试一下。。。谢谢你千方百计的解释。这些概念对我们初学者来说有点难,即使我在Java方面很有经验,拥有不可变对象需要一个非常不同的视角。所以神奇的短语是它是一个抽象类型成员而不是一个类型参数,并且它的类型绑定为Employee的一个子类。Scala书中的编程有一整节是关于成员和参数的。我是Scala的初学者,所以我可能遗漏了一些重要的设计原则。我努力想弄明白的是如何实现传统的OO多态性
同时保持数据对象不变。这将是一个典型的例子:Employee作为一个抽象类,它有名称和employeeId,还有一些类扩展它,比如Technician和Manager。更新名称或employeeId的方法必须创建另一个相同类型的实例(如果它是不可变的)。另一方面,系统的其余部分有一些方法,这些方法可以接受employees。在这种情况下,您可以将Employee作为trait,并为technology和Manager创建case类子类型。像对commonUpdateFunction那样声明withName和withId,然后根据copy方法在case类中定义。我想知道您是否希望commonFunction和commonUpdateFunction在您的示例中是相同的东西;因为现在他们非常不同,我错了,他们应该是一样的。固定的是的,我明白了,问题出现在其他地方,我只需要使用Employee作为一个完全无关类的方法的参数。它不在乎自己是什么类型的员工。现在我只是得到了一些错误,说它需要指定类型,我想是因为[T]的东西,它是用来确定不可变类的真正类型的。所以您声明了一个内部类型,它被具体类重写。。。好把戏!我会尝试一下。。。谢谢你千方百计的解释。这些概念对我们初学者来说有点难,即使我在Java方面很有经验,拥有不可变对象需要一个非常不同的视角。所以神奇的短语是它是一个抽象类型成员而不是一个类型参数,并且它的类型绑定为Employee的一个子类。Scala书中的编程有一整节是关于成员和参数的。