Scala类型的多态性

 linxin66063 发布于 2023-02-12 15:48

我们正在重构继承method以使用类型类 - 我们希望将所有method实现集中在一个地方,因为将它们分散在实现类中会使维护变得困难.但是,我们遇到了一些麻烦,因为我们对类型类很新.目前method被定义为

trait MethodTrait {
  def method: Map[String, Any] = // default implementation
}

abstract class SuperClass extends MethodTrait {
  override def method = super.method ++ // SuperClass implementation
}

class Clazz extends SuperClass {
  override def method = super.method ++ // Clazz implementation
}

等等,总共有50多个具体类,层次结构相当浅(abstract class SuperClass- > abstract class SubSuperClass- > abstract class SubSubSuperClass- > class ConcreteClass就像它一样深),具体类永远不会扩展另一个具体类.(在实际实现中,method返回一个Play框架JsObject而不是一个Map[String, Any].)我们试图用类型类替换它:

trait MethodTrait[T] {
  def method(target: T): Map[String, Any]
}

class MethodType {
  type M[T] = MethodTrait[T]
}

implicit object Clazz1Method extends MethodTrait[Clazz1] {
  def method(target: Clazz1): Map[String, Any] { ... }
}

implicit object Clazz2Method extends MethodTrait[Clazz2] {
  def method(target: Clazz2): Map[String, Any] { ... }
}

// and so on

我遇到两个问题:

.模仿super.method ++先前实现的功能.目前我正在使用

class Clazz1 extends SuperClass

class Clazz2 extends SubSuperClass

private def superClassMethod(s: SuperClass): Map[String, Any] = { ... }

private def subSuperClassMethod(s: SubSuperClass): Map[String, Any] = {
  superClassMethod(s) ++ ...
}

implicit object Clazz1Method extends MethodTrait[Clazz1] {
  def method(target: Clazz1): Map[String, Any] = { 
    superClassMethod(target) ++ ... 
  }
}

implicit object Clazz2Method extends MethodTrait[Clazz2] {
  def method(target: Clazz2): Map[String, Any] = { 
    subSuperClassMethod(target) ++  ... 
  }
}

但这很难看,如果我不小心将方法调用到层次结构太远的地方,我就不会收到警告或错误,例如,如果Clazz2调用superClassMethod而不是subSuperClassMethod.

.召唤method一个超类,例如

val s: SuperClass = new Clazz1()
s.method

理想情况下,我希望能够告诉编译器每个子类在类型类中SuperClass都有对应的隐式对象method,因此s.method是类型安全的(或者如果我忽略了实现一个,我将得到一个编译时错误对于子类的相应隐式对象SuperClass,但是我已经能够想到的是

implicit object SuperClassMethod extends MethodTrait[SuperClass] {
  def method(target: SuperClass): Map[String, Any] = { 
    target match {
      case c: Clazz1 => c.method
      case c: Clazz2 => c.method
      ...
    }
  }
}

这是丑陋的,如果我省略了一个类,我不会给我编译时警告或错误,因为我无法定义SuperClass为密封特征.


我们愿意接受类型类的替代方法,这样我们就可以将method代码集中在一个地方. method只从两个地方召集:

A.其他method实现,例如Clazz1有一个val clazz2: Option[Clazz2],在这种情况下,method实现Clazz1将是类似的

def method = super.method ++ /* Clazz1 method implementation */ ++ 
  clazz2.map(_.method).getOrElse(Map())

B.顶级Play Framework控制器(即所有控制器继承的抽象类),我们在其中定义了三个ActionBuilders调用method,例如

def MethodAction[T <: MethodTrait](block: Request[AnyContent] => T) = {
  val f: Request[AnyContent] => SimpleResult = 
    (req: Request[AnyContent]) => Ok(block(req).method)

  MethodActionBuilder.apply(f)
}

0__.. 6

我认为类型类与您的场景不兼容.当类型不相交时,它们很有用,但实际上要求实例反映超类型/子类型层次结构并且不是独立的.

通过这种重构,您只是创建了挑选错误实例的危险:

trait Foo
case class Bar() extends Foo

trait HasBaz[A] { def baz: Set[Any] }

implicit object FooHasBaz extends HasBaz[Foo] { def baz = Set("foo") }
implicit object BarHasBaz extends HasBaz[Bar] { def baz = FooHasBaz.baz + "bar" }

def test[A <: Foo](x: A)(implicit hb: HasBaz[A]): Set[Any] = hb.baz

val bar: Foo = Bar()
test(bar) // boom!

所以你最终用你的模式匹配器重写了多态分派SuperClassMethod.你基本上去OO - > FP - > OO,同时渲染类型类的想法不可用(要打开),最后是和类型(已知的所有子类型).

1 个回答
  • 我认为类型类与您的场景不兼容.当类型不相交时,它们很有用,但实际上要求实例反映超类型/子类型层次结构并且不是独立的.

    通过这种重构,您只是创建了挑选错误实例的危险:

    trait Foo
    case class Bar() extends Foo
    
    trait HasBaz[A] { def baz: Set[Any] }
    
    implicit object FooHasBaz extends HasBaz[Foo] { def baz = Set("foo") }
    implicit object BarHasBaz extends HasBaz[Bar] { def baz = FooHasBaz.baz + "bar" }
    
    def test[A <: Foo](x: A)(implicit hb: HasBaz[A]): Set[Any] = hb.baz
    
    val bar: Foo = Bar()
    test(bar) // boom!
    

    所以你最终用你的模式匹配器重写了多态分派SuperClassMethod.你基本上去OO - > FP - > OO,同时渲染类型类的想法不可用(要打开),最后是和类型(已知的所有子类型).

    2023-02-12 15:50 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有