Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.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 Pimp my library模式应用于类层次结构_Scala_Polymorphism_Implicit - Fatal编程技术网

Scala Pimp my library模式应用于类层次结构

Scala Pimp my library模式应用于类层次结构,scala,polymorphism,implicit,Scala,Polymorphism,Implicit,我有下面的类层次结构 sealed abstract class A case class B extends A case class C extends A 现在,我想在类a、B和C中添加foo方法。但我不想以任何方式改变课程。因此,我应用pimp my library模式如下 abstract class RichA(a: A) { def foo } class RichB(b: B) extends RichA(b){ def foo = { println("B")

我有下面的类层次结构

sealed abstract class A
case class B extends A
case class C extends A
现在,我想在类
a
B
C
中添加
foo
方法。但我不想以任何方式改变课程。因此,我应用pimp my library模式如下

abstract class RichA(a: A) {
    def foo
}
class RichB(b: B) extends RichA(b){
    def foo = { println("B"); //do something with b}
}
class RichC(c: C) extends RichA(c) {
    def foo = { println("C"); //do something with c}
}
/////////////
implicit def A2RichA(a: A) = {
    a match {
    case a: B => new RichB(a)
    case a: C => new RichC(a)
    }
}
implicit def B2RichB(b: B) = new RichB(b)
implicit def C2RichC(c: C) = new RichC(c)
/////////////
def test() = {
    def printA(a: A) = {
        a.foo
    }
    val obj = new C
    printA(obj)
}
test() //This prints "C"

这是可行的,但是
A2RichA
隐式函数的实现在我看来有点难看,因为它涉及到A的每个子类的case语句。这能以更优雅的方式完成吗?基本要求是,如果我对类型为
a
的对象调用
foo
,它应该在
B
C
中调用适当的方法
foo
,具体取决于对象的动态类型。

第一种方法:--根据操作要求不足--

假设
foo
的单个实现适合您层次结构中的所有类,那么就可以了:

sealed abstract class A
case class B() extends A
case class C() extends A

class RichA(a: A) {
  def foo() { println(this.a.getClass.getSimpleName) }
}

implicit def a2RichA(a: A): RichA = new RichA(a)

(new C).foo() /* anon$1$C */

第二种方法:——缺乏动态调度--

我的第二种方法受到了该方法内部的启发。但是,它缺乏动态调度,因此仍然无法解决您的问题

sealed abstract class A
case class B() extends A
case class C() extends A

abstract class RichA(a: A) {
  def foo(): Unit
}

class RichB(b: B) extends RichA(b) {
  def foo() { println("Doing B-specific stuff") }
}

class RichC(c: C) extends RichA(c) {
  def foo() { println("Doing C-specific stuff") }
}

sealed trait RichBuilder[T <: A] {
  def apply(t: T): RichA
}

implicit object RichB extends RichBuilder[B] {
  def apply(b: B) = new RichB(b)
}

implicit object RichC extends RichBuilder[C] {
  def apply(c: C) = new RichC(c)
}

implicit def a2RichA[T <: A](t: T)
                            (implicit rb: RichBuilder[T])
                            : RichA = {

  rb(t)
}

(new B).foo() /* B-specific */
(new C).foo() /* C-specific */
// (new C).asInstanceOf[A].foo() /* ERROR: Can't find an implicit */
密封抽象类A
case类B()扩展了
case类C()扩展了
抽象类RichA(a:a){
def foo():单位
}
类RichB(b:b)扩展了RichA(b){
def foo(){println(“做特定于B的事情”)}
}
类RichC(c:c)扩展了RichA(c){
def foo(){println(“做C特定的东西”)}
}

sealed trait RichBuilder[T通过允许编译器提供正确的转换,您可以使您的
A2RichA
方法稍微优雅(或难以捉摸,取决于您的视角):

implicit def A2RichA(a: A): RichA = 
   a match {
      case b: B => b // the compiler turns this into B2RichB(b)
      case c: C => c // the compiler turns this into C2RichC(c)
   }

implicit def B2RichB(b: B): RichA = new RichB(b)

implicit def C2RichC(c: C): RichA = new RichC(c)
但是,我不认为有更简单的方法可以解决这个基本问题:您希望提供基于参数的动态类型的转换。隐式搜索发生在编译时,因此只能提供基于静态类型的转换

您可以在运行时反射式地搜索转换,但这既不简单也不优雅(对于这样一个小的层次结构来说当然是不可取的)


由于您的层次结构是密封的,如果您在向层次结构中添加新类时忘记提供转换,编译器将向您发出警告。

是否要将相同的
foo
添加到您的类中,或者是否需要为
a、B、C
中的每一个都使用不同的实现?抱歉,我将问题简化得太多。
B
C
可以有不同的数据,
foo
的实现对于
B
C
是不同的。因为我的方法并不能真正解决问题-每个人,请反驳我的说法。谢谢你的指点..我需要一些时间来消化。
sealed abstract class A
case class B extends A
case class C extends A