scala:如何使用泛型实例查看子类方法

时间:2013-09-04 22:09:53

标签: scala

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

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'的成员。所以我的问题是如何使DataScheme的Subtraits中的ExtractorMethods的子类像IndexScheme一样可以访问?如何使用Manifest和TypeTag?感谢。

1 个答案:

答案 0 :(得分:0)

因此,您希望泛型类Data [DataScheme]或Data [IndexScheme]能够访问已经参数化的数据类型的方法。您已经尝试过几种不同的方式,从代码中的证据开始。

要回答您的上一个问题 - 在这种特殊情况下,清单无法帮助,而TypeTag只是答案的一部分。如果您真的想这样做,可以使用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和b的类,但是v2.t.methods给了一个方法一和二的类。

这真的不是如何做到这一点 - 为这种工作寻求反思显示出一个非常破碎的模型。但我猜这是你的事。

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

原始回答

好吧,我首先要说的是,我永远不会按照你这样做的方式做事;它看起来非常复杂。但你可以通过

按照你的方式做你想做的事
  1. 使用mixins
  2. 将extractorMethods创建代码移动到特征中。
  3. 这是一个非常简化的例子:

    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只有 a b 方法,但v2.myMethods会有 a ,< strong> b ,一个两个

    您应该能够看到如何使其适应您自己的班级和特质结构。我知道我的例子中没有任何复杂的类型逻辑,但你比我更了解你想要实现的目标。我只是想展示一个简单的机制。

    但是老兄,这样可以让你的生活变得困难......

    修改

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

    1. 您无法在数据类中执行您要执行的操作,因为它是抽象的。您不能强制Scala用特定类型神奇地替换非特定类型的未初始化的抽象方法,只需使用类型注释乱丢所有内容即可。您只能通过提供特定类型的具体类来解决此问题。

    2. 您应该使用隐式转换执行此操作。 Implicits可以帮助您以错误的方式执行此操作,但也可以帮助您以正确的方式执行此操作。哦,并使用伴侣对象,无论是暗示还是持有工厂(或机器人)。