-1

我有以下内容,我为不同的数据方案设置信息和提取器:

trait DataScheme {
    type Type <: List[Any]
    class ExtractorMethods(ticker: String, dataList: List[Type]) {
        def getDatetime(datum: Type): Date = new Date(datum(columnIndex(Names.datetime)).toString)
        def upperDatum(date: Date): Type = dataList.minBy(datum => getDatetime(datum) >= date)
        def lowerDatum(date: Date): Type = dataList.maxBy(datum => getDatetime(datum) <= date)
    }
}
trait IndexScheme extends DataScheme {
    type Type = (Date, Double, Double, Double, Double, Long)
    class ExtractorMethods(ticker: String, dataList: List[Type]) extends super.ExtractorMethods(ticker: String, dataList: List[Type]){
        def testing12(int: Int):Int = 12
        val test123 = 123
    }
}

我想要任何扩展 DataScheme 以使用其 ExtractorMethods 方法(例如 lowerDatum)但也有自己的方法(例如 testing12)。

数据元素列表有一个类定义:

class Data[+T <: DataScheme](val ticker: String, val dataList: List[T#Type], val isSorted: Boolean)
    (implicit m: Manifest[T], mm: Manifest[T#Type]) extends Symbols {
    def this(ticker: String, dataList: List[T#Type])(implicit m: Manifest[T], mm: Manifest[T#Type]) = this(ticker, dataList, false)(m: Manifest[T], mm: Manifest[T#Type])
    val dataScheme: T
    val extractorMethods = new dataScheme.ExtractorMethods(ticker, dataList.asInstanceOf[List[dataScheme.Type]])
}

Data 类应该使方案的 ExtractorMethods 中的方法可以访问,以便它们可以通过已定义的 Data 实例在主程序中使用。例如,如果 sortedData 是 Data[IndexScheme] 的一个实例,则以下工作:

val lowerDatum = sortedData.extractorMethods.lowerDatum(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2010-03-31 00:00:00"))

但这不会:

val testing = sortedData.extractorMethods.testing12(123)

因为“测试 123 不是 sortedData.dataScheme.extractorMethods 的成员”。所以我的问题是如何使 IndexScheme 等 DataScheme 的子特征中的 ExtractorMethods 的子类可以访问?如何使用 Manifests 和 TypeTags?谢谢。

4

1 回答 1

0

因此,您希望泛型类 Data[DataScheme] 或 Data[IndexScheme] 能够访问已参数化的任何类型Data的方法。根据代码中的证据,您尝试了几种不同的方法。

要回答您的最后一个问题 - 在这种特殊情况下清单无济于事,TypeTags 只是答案的一部分。如果你真的想这样做,你可以用mirrors来做。

但是,您必须对代码进行一些更改。Scala 只有实例方法;Scala 中没有静态方法之类的东西。这意味着您只能使用反射来调用类、特征或对象的实例上的方法。您的特征是抽象的,无法实例化。

我无法真正告诉您如何清理代码,因为您在此处粘贴的内容有些混乱,并且充满了您尝试过的不同内容。我可以向您展示的是如何使用一组更简单的类来做到这一点:

import scala.reflect.runtime.universe._

class t1 {
  class Methods {
    def a = "a"
    def b = "b"
  }
  def methods = new Methods
}

class t2 extends t1 {
  class Methods extends super.Methods {
    def one = 1
    def two = 2
  }
  override def methods = new Methods
}

class c[+T <: t1](implicit tag: TypeTag[T]) {

  def generateT = {
    val mirror = runtimeMirror(getClass.getClassLoader)
    val cMirror = mirror.reflectClass(typeOf[T].typeSymbol.asClass)
    cMirror.reflectConstructor(typeOf[T].declaration(nme.CONSTRUCTOR).asMethod)
  }
  val t = generateT().asInstanceOf[T]
}

val v1 = new c[t1]
val v2 = new c[t2]

如果你运行它,你会发现它v1.t.methods为你提供了一个只有方法 a 和 bv2.t.methods的类,但也提供了一个具有方法一和二的类。

这真的不是如何做到这一点 - 为这种工作进行反思表明了一个非常破碎的模型。但我想那是你的事。

不过,我坚持我在下面所说的话。您应该对伴随对象使用隐式转换(可能还有隐式参数)。按照设计的方式使用 Scala 的类型系统——你一直在与它作斗争。

原始答案

好吧,我首先要说的是,我永远不会像您那样做事;这似乎过于复杂了。但是你可以做你想做的事,大致按照你做的方式,通过

  1. 使用混合
  2. 将 extractorMethods 创建代码移动到特征中。

这是一个大大简化的示例:

trait t1 {
  class Methods {
    def a = "a"
    def b = "b"
  }
  def methods = new Methods
}

trait t2 extends t1 {
  class Methods extends super.Methods {
    def one = 1
    def two = 2
  }
  override def methods = new Methods
}

class c1 extends t1 
val v1 = new c1
// v1.methods.a will return "a", but v1.methods.one does not exist
class c2 extends c1 with t2
val v2 = new c2
// v2.methods.a returns "a" and v2.methods.one returns 1

我可以通过像这样定义c1来更紧密地复制您的作案手法:

class c1 extends t1 {
  val myMethods = methods
}

在这种情况下v1.myMethods,只有方法abv2.myMethods会有abonetwo

您应该能够看到如何使其适应您自己的类和特征结构。我知道我的示例中没有任何复杂的类型逻辑,但是您比我更清楚您要在那里实现的目标。我只是想演示一个简单的机制。

但是伙计,让你的生活变得困难的方法......

编辑

关于你的方法有什么问题,我可以说很多事情,无论是小规模还是大规模。我将限制自己说两件事:

  1. 你不能在Data类中做你想做的事情,因为它是抽象的。你不能强迫 Scala 用特定类型神奇地替换非特定类型的未初始化的抽象方法,只需用类型注释乱扔所有东西。您只能使用提供特定类型的具体类来解决此问题。

  2. 您应该使用隐式转换来执行此操作。Implicits 会帮助你以你看起来固执的错误方式去做,但也会帮助你以正确的方式去做。哦,使用伴生对象,无论是用于隐式还是保存工厂(或机器人)。

于 2013-09-05T12:33:13.770 回答