【问题标题】:Type-parametrized class with default type parameter具有默认类型参数的类型参数化类
【发布时间】:2012-06-19 21:52:04
【问题描述】:

例如,我有以下类层次结构:

abstract class A {
  def a() {}
  def aa()
}

class B extends A {
  def aa() {}
  def b()
}

class C extends A {
  def aa() {}
  def c()
}

然后我想创建一个类,它可以存储这些类实例的任意组合的集合。它将能够调用常用方法。并且由于类型参数化,如果在创建期间使用这些类进行参数化,它必须提供调用特定于类的方法的能力:

object Group {

  def apply(as: Buffer[A]) = new Group[A](as)
  def apply[T <: A](as: Buffer[T]) = new Group[T](as)
}

class Group[T <: A](as: Buffer[T]) {

  def a() { as.map(_.a()) }
  def aa() { as.map(_.aa()) }

}

所以Group 可以使用默认的、最通用的类​​型参数来创建,如下所示:

val groupA = Group(Buffer[A]())
groupA.a()  //ok
groupA.aa() //ok
groupA.b()  //error
groupA.c()  //error

它可以在使用A 的后代之一显式参数化时创建:

val groupB = Group[B](Buffer[B]())
groupB.a()  //ok
groupB.aa() //ok
groupB.b()  //ok
groupB.c()  //error

如果可能的话,我想在创建组时以某种方式删除不必要的 [B] 类型规范,因为它可以从传递的缓冲区类型中提取:

val groupB = Group(Buffer[B]())

实现此功能的正确方法是什么?可能吗?也许有更好的架构决策来实现这一点?

更新:这里的代码是伪代码,我就是不知道怎么写。

更新2:我猜想调用b()c()等特定类型的方法应该通过映射来实现:

groupC.as.map(_.c())

这是只有可能的,如果类型参数化是正确的。这更接近我的想法,但具体可能的实现方式仍然是个谜(除了asInstanceOf 事物的一堆用法)..

【问题讨论】:

  • 也许使用您的Group[C] 隐式转换为具有c() 方法的东西,这仅在参数为C 时适用?
  • @ziggystar:也许吧,但你能举个例子吗?我不确定我能不能这样理解。

标签: scala


【解决方案1】:

您可以使用隐式转换来看似仅将方法添加到Group 的那些使用正确类型参数化的实例。这可以被认为是pimp my library 模式的选择性版本。

scala> abstract class A { def a() {}; def aa() {} }
defined class A

scala> class B extends A {def b() {}}
defined class B

scala> class C extends A {def c() {}}
defined class C

现在我定义Group 类。注意 Group[C] 的隐式转换,它添加了 c() 方法。这种转换不适用于例如Group[A] 值。

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Group[T <: A](as: Seq[T])
object Group{implicit def forC(gc: Group[C]) = new {def c() {gc.as.map(_.c())}}}

// Exiting paste mode, now interpreting.

defined class Group
defined module Group

现在让我们看看它是否有效。

scala> val groupC = Group(new C :: new C :: Nil)
groupC: Group[C] = Group(List(C@7f144c75, C@da7d681))

scala> groupC.c()  //works

scala> val groupB = Group(new B :: new B :: Nil)
groupB: Group[B] = Group(List(B@e036122, B@7fde065d))

scala> groupB.c()  //fails as expected
<console>:16: error: value c is not a member of Group[B]
              groupB.c()
                     ^

【讨论】:

  • 那肯定好多了!但是,对不起,我有一些问题 =) : 1) case class Group 只做 case 类,因为调用自动创建的as 方法很方便? 2)您提到c() 方法不会产生任何结果。为什么这很重要?你的意思是这纯粹是副作用,这无济于事吗? 3) 我在哪里可以阅读更多关于您在此处使用的implicit 表单以及用于无名类的new {} 构造?这种形式是否自动意味着无名类实例 (?) 将继承 Group[C] 中的内容?
  • 1) case 上课方便;它还将apply 添加到您手动执行的同伴中。 2)是的,评论有点误导。我添加了它,所以读者不会想知道输出在哪里。没有,因为该方法什么都不做。您可以在c() 中做任何您想做的事情。 3) 模式名为Pimp my library;你也可以命名类。并且它不会从C 继承东西,除非您添加extends C
猜你喜欢
  • 2018-02-18
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
相关资源
最近更新 更多