2013-09-04 3 views
-1

У меня есть следующий, где я поставил информацию и экстракторы для различных схем данных: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), но также имеют свои собственные методы (например, тестирование12).

Существует определение класса для списков элементов данных:

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]]) 
} 

класса А Данные должны сделать доступными методы в ExtractorMethods схемы, так что они могут быть использованы в основной программе через экземпляр данных, которые была определена. Например, если sortedData является экземпляром данных [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 ». Поэтому мой вопрос в том, как можно сделать доступными подклассы ExtractorMethods в подзаголовках DataScheme, таких как IndexScheme? Как это возможно с помощью Manifests и TypeTags? Благодарю.

+0

ExtractorMethods - отличное название для этого класса. Вероятно, это будет источником первоначальной путаницы для всех, кто должен прочитать ваш код, учитывая, что ** extractor ** - такой известный термин в Scala. – itsbruce

+1

Кстати, как это даже скомпилировать? Вы не должны переопределять тип Type: List [Any] 'с типом Type = (Date, Double, Double, Double, Double, Long)'. Кортежи не являются подтипом 'List [Any]'. Какую версию Scala вы используете? – itsbruce

+0

Кроме того, как класс Data компилируется, когда он кажется абстрактным? Хотя у вас нет абстрактного ключевого слова. ** dataScheme ** val, кажется, не создается, что вынуждает класс быть абстрактным. Вы действительно скомпилировали этот код? Имеет ли ** dataScheme ** val какие-либо цели, кроме как предоставить правильную версию метода ExtractorMethods? – itsbruce

ответ

0

Таким образом, вы хотите, чтобы общий класс Data [DataScheme] или Data [IndexScheme] имел доступ к методам любого типа Данные были параметризованы. Вы пытались сделать это несколько разных способов, из доказательств вашего кода.

Чтобы ответить на ваш последний вопрос - манифесты не могут помочь в данном конкретном случае, и 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 дает класс с только методы а ​​и б, но v2.t.methods дает класс с методами один и два.

Это не так, как это сделать - достижение отражения для такого рода работ показывает очень сломанную модель. Но я думаю, это ваше дело.

Я придерживаюсь того, что я сказал ниже. Вы должны использовать неявные преобразования (и, возможно, неявные параметры) с сопутствующими объектами. Используйте систему типа Scala так, как она разработана - вы сражаетесь с ней полностью.

ОРИГИНАЛЬНЫЙ ОТВЕТ

Ну, я собираюсь начать с того, что я никогда не делал бы вещи так, как вы делаете это; это кажется ужасно сложным.Но вы можете делать то, что вы хотите сделать, примерно так, как вы делаете это, по

  1. Использование Mixins
  2. Moving код создания 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 бы только методы a и b но v2.myMethods будет иметь a, b, один и .

Вы должны уметь видеть, как вы можете адаптировать это к своей собственной структуре классов и признаков. Я знаю, что мой пример не содержит в себе какой-либо сложной логики, но вы знаете лучше, чем я пытаюсь достичь там. Я просто пытаюсь продемонстрировать простой механизм.

Но чувак, способ сделать вашу жизнь трудной ...

EDIT

Есть так много вещей, которые я мог бы сказать о том, что случилось с вашим подходом здесь, как на малых и больших масштаб. Я буду ограничивать себя говоря две вещи:

  1. Вы не можете делать то, что вы пытаетесь сделать в классе данных, поскольку она является абстрактным. Вы не можете заставить Scala магически заменить неинициализированный абстрактный метод неспецифического типа с конкретным типом, просто засоряя все аннотации типа. Вы можете решить это только конкретным классом, который предоставляет определенный тип.

  2. Вы должны делать это с неявными преобразованиями. Implicits поможет вам сделать это неправильно, как вы, кажется, зациклились, но также поможет вам сделать это правильно. О, и используйте сопутствующий объект, либо для имплицитов, либо для хранения фабрики (или бота).

+0

Во-первых, должна быть только потребность в классе Data [+ T <: DataScheme], поэтому я поставил типа на нем. Not Data1 расширяет t1, Data2 расширяет t2 и т. Д. Я хочу простоту; но я хочу сделать код абстрактным и не дублировать код снова и снова. Во-вторых, я создаю экземпляр класса ExtractorMethods с параметрами, поэтому это невозможно сделать в признаке. Да, я могу использовать вашу идею создания класса Data1 extends t1 и создания экземпляров ExtractorMethods в нем, возможно, отдельно от этого признака, но снова хочу избежать повторного дублирования класса. Так это возможно? – user2748572

+0

Я могу «ответить на ваш вопрос конкретно, пока вы не дадите дополнительные ответы (см. Комментарии, добавленные к исходному вопросу выше). Ваш код даже не выглядит так, как будто он должен компилироваться. Это также очень, очень вонючий (в плохой код пахнет). В общем, я бы сказал, что лучший способ получить уровень абстракции, который вы хотите, - это использовать фабрику (возможно, скрытую в сопутствующем объекте), чтобы сгенерировать classe – itsbruce

+0

О, и «Я создаю экземпляр класса ExtractorMethods с параметрами, поэтому это не может делать в признаке "не имеет смысла. Конечно, это можно сделать. – itsbruce

Смежные вопросы