2015-04-14 3 views
0

Например, у меня есть код выглядит следующим образом:Определите тип параметра во время выполнения в Scala

class Parent 
class Child1 extends Parent 
class Child2 extends Parent 

class Foo { 

    def retrieve(arg: String): List[Parent] = { 
    arg match { 
     case "Child1" => get[Child1]() 
     case "Child2" => get[Child2]() 
    } 
    } 

    def get[T: Manifest](): List[T] = ... 

} 

В методе retrieve, я хочу, чтобы упростить код в один get вызов метода только, как это:

def retrieve(arg: String): List[Parent] = { 
    val t = arg match { 
     case "Child1" => ? 
     case "Child2" => ? 
    } 

    get[t]() 
    } 

Можно ли достичь этого в scala?

UPDATE:

Я попробовал решение от ответа здесь, но у меня проблема, она не работает с перегруженной get способом, например:

def get[T: Manifest](x: String): List[T] = ... 

def get[T: Manifest, U: Manifest](x: String): List[(T, U)] = ... 

К примеру, в retrieve:

val t = arg match { 
    case "Child1" => manifest[Child1] 
    case "Child2" => manifest[Child2] 
} 

get("test")(t) 

Я получил ambiguous reference to overloaded definition ошибку компиляции на линии get("test")(t).

+0

Возможный дубликат [Как обойти стирание стилей на Scala? Или, почему я не могу получить параметр типа моих коллекций?] (Http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why -cant-i-get-the-type-paramete) – johanandren

+2

Это не дубликат этого вопроса, он уже использует манифест. –

+2

И он не хочет знать, как обойти стирание стилей, который он хочет узнать о реализации функции get каким-то другим способом. – curious

ответ

3

Ваш вопрос сводится к тому, как получить Manifest данного типа. Это можно сделать, используя метод manifest. Затем вы можете явно пропустить манифест, до get.

class Foo { 
    def retrieve(arg: String): List[Parent] = { 
    val t = arg match { 
     case "Child1" => manifest[Child1] 
     case "Child2" => manifest[Child2] 
    } 

    get(t) 
    } 

    def get[T <: Parent: Manifest]: List[T] = ... 
} 

Как примечание стороны, вы, вероятно, следует использовать карту, чтобы получить манифестов (а не сопоставления с образцом), чтобы сделать его более легко редактируются, или, возможно, в одной точке, заменяющего жестко запрограммированный список типов с некоторой инициализации времени вычисления:

object Foo { 
    private val manifestByName = Map[String, Manifest[_<:Parent]](
    "Child1" -> manifest[Child1], 
    "Child2" -> manifest[Child2] 
) 
} 
class Foo { 
    def retrieve(arg: String): List[Parent] = { 
    val t = Foo.manifestByName.getOrElse(arg, sys.error(s"Invalid class name $arg")) 
    get(t) 
    } 

    def get[T <: Parent: Manifest]: List[T] = { println(manifest[T]); Nil } 
} 

Наконец, отметим, что Manifest теперь осуждается, он был заменен с ClassTag \ TypeTag.

+0

Спасибо. Интересно, не имеет ли метод 'get'' ': Manifest' или' ClassTag' в '[T]', возможно ли еще выполнить передачу параметров типа? – null

+0

См. Раздел ** ОБНОВЛЕНИЕ ** на вопрос, я получил «неоднозначную ошибку ссылки». – null

2

Manifest в основном deprecated. :

В Scala 2.10 scala.reflect.ClassManifests являются устаревшими, и это планируется принизить scala.reflect.Manifest в пользу TypeTags и ClassTags в следующем выпуске точки. Таким образом, желательно, чтобы перенесли любые API-интерфейсы на основе манифеста, чтобы использовать теги.

Вы должны рассмотреть возможность использования более современных ClassTag или TypeTag. В этом случае, ClassTag работает лучше (с TypeTags не могут быть использованы в сопоставлении с образцом):

def retrieve(arg: String): List[Parent] = { 
    val t = arg match { 
     case "Child1" => classTag[Child1] 
     case "Child2" => classTag[Child2] 
    } 

    get(t) 
} 

def get[T : ClassTag]: List[T] = list collect { 
    case x: T => x 
} 

Вы можете прочитать больше о ClassTags, TypeTags, и их отношения к Manifest в документации here.

В случае, если это не ясно, что это работает, потому что тип ограничение на T является контекстом связан, то есть метод подпись get эквивалентна:

def get[T](implicit ev: ClassTag[T]): List[T] 

Итак, когда мы называем get(t), мы 'явно указывая неявный параметр. Подробнее о границах контекста here.

Если контекст связан или неявный параметр является запутанным, вы можете достичь своих целей пути get необщими:

def get(c: ClassTag[_]) = list collect { 
    case x if ClassTag(x.getClass) == c => x 
} 

Это не унифицированная, не неявная версия может помочь вам решить ваш перегружать вопрос ,

+0

Спасибо. Интересно, не имеет ли метод 'get'' ': Manifest' или' ClassTag' в '[T]', возможно ли еще выполнить передачу параметров типа? – null

+0

Пожалуйста, см. Раздел ** ОБНОВЛЕНИЕ ** на вопрос, я получил «неоднозначную ошибку ссылки». – null

+0

@suud Я добавил обновление, которое позволяет сделать 'get' неэквивалентным. Что касается вашего обновления, я чувствую, что это новый вопрос! –

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