【问题标题】:Scala generic class designScala 通用类设计
【发布时间】:2018-04-14 17:25:53
【问题描述】:

所以我有以下情况。首先是一个类层次结构 A

trait A
trait B extends A
class C extends B

我还有一个类,它的泛型参数定义为 [T <: a>

class Foo[T <: A]

这个类定义了两个接受T类型对象的方法

def single(t: T): Bar
def multiple(lt: List[T]): Bars

如果对象tlt 都是从B 派生的类型,则这些方法中的这些方法调用另一个采用tlt(映射其元素)的方法,对其进行一些修改(这取决于类型本身)并吐出相同的对象

def update[P <: B](op: P, item: Item): P = {
  if (item.field1..) op.field1 = item.field1
  if (item.field2..) op.field2 = item.field2
  ...

  op match {
    case c: C => 
      if (item.field123 ...) c.field123 = item.field123
  }

  op
}

我不喜欢这种方法现在的方式,因为它会对对象进行突变。当我遵循函数式编程风格时,我设法保持代码库不可变和可组合。

我更愿意将字段分配推送给构造函数并基于它们的父类构建对象,但由于 Scala 的辅助构造函数调用方案,我找不到这样做的方法。另一种方法是拥有一个案例类并使用复制构造函数,但我不能这样做,因为我需要保持 A、B 和 C 可扩展。

我希望我能够很好地描述我的场景。如果您需要更多说明 - 请询问。我将不胜感激。

【问题讨论】:

  • object 是保留关键字,这不能是可编译的MCVE
  • 我会使用类型类来设计它。现在无法提供代码。如果没有人帮助,稍后会添加一个示例。
  • @simpadjo 将不胜感激!

标签: scala oop generics


【解决方案1】:

类型类来救援

object Example {

  trait Item

  // generic interface that makes possible for T
  // to be updated by an Item
  // Better to return a new object here instead of mutating an old one
  trait Updater[T] {
    def update(obj: T, item: Item): T
  }

  class B1

  class B2

  implicit val b1Updated: Updater[B1] = new Updater[B1] {
    override def update(obj: B1, item: Item): B1 = {
      println("B1 updater called")
      //your code for b1 here
      ???
    }
  }

  implicit val b2Updated: Updater[B2] = new Updater[B2] {
    override def update(obj: B2, item: Item): B2 = {
      println("B2 updater called")
      //your code for b2 here
      ???
    }
  }

  //whenever you add a new class that has to be updatable you must provide such instance of Updater[MyNewB]
  //But you don't have to declare it right here so it's still modular


  //works for every type T that has implicit instance of type Updater[T]
  def updateOne[T: Updater](obj: T, item: Item): T = {
    implicitly[Updater[T]].update(obj, item)
  }

  def updateList[T: Updater](lst: List[T], item: Item): List[T] = {
    val updater = implicitly[Updater[T]]
    lst.map(e => updater.update(e, item))
  }

  def main(args: Array[String]): Unit = {
    val list: List[B1] = List(new B1, new B1)
    updateList(list, new Item {})
  }
}

【讨论】:

  • 这很好,但现在我的测试抱怨他们“找不到隐含的值”。当我正在编写一个库时,我不想强​​迫客户添加隐式导入。我读到implicitly 会解决隐含,只要它们在范围内,但到目前为止还没有发生。
  • implicitly 确实解析了范围内的隐式值。如果不是 - 那么值超出范围。在这里stackoverflow.com/questions/5598085/…,您可以了解编译器在哪里查找隐式值。在您的情况下,将隐式值放入 object Updater{...} 可能会很方便
猜你喜欢
  • 2011-11-29
  • 2019-08-20
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 2012-02-24
  • 1970-01-01
相关资源
最近更新 更多