#generics #scala
#обобщения #scala
Вопрос:
Я использую стороннюю библиотеку, и сигнатура метода является:
def parse[A](input: String)(implicit mf: Manifest[A]): A = ...
Я знаю только A
во время выполнения. Как мне вызвать parse
метод, приведенный выше, с A
представлением в виде строки?
Является ли единственный вариант подходящим для всех объектов моего домена?
Например.
object ParserHelper {
def apply(clazz: String, arg: String) = clazz match {
case "DomainObjectA" => parse[DomainObjectA](arg)
case "DomainObjectB" => parse[DomainObjectB](arg)
case _ => throw new RuntimeException("Domain class %s not mapped" format clazz)
}
}
… и затем вызываете ParserHelper("com.example.DomainObjectA", "some argument")
?
Т.е. как мне вызвать parse[???]("")
where??? динамически создается во время выполнения из строки, подобной "com.example.SomeDomainObject"
?
Комментарии:
1. обобщения — это механизм проверки типов во время компиляции. Генерация универсального типа во время выполнения вообще не имеет никакого смысла.
2. отличается ли манифест для каждого типа? если это так, вы можете попробовать создать map<строка, манифест>, где ключом является classname, и явно передать параметр manifest для parse[?](аргумент, манифест). На самом деле я не знаю, сработает ли это, но, возможно, стоит попробовать.
3. Спасибо за комментарии, Кевин. Смотрите мой комментарий к принятому ответу. Я слишком долго смотрел на этот монитор 🙂
Ответ №1:
Я не думаю, что это возможно. Во время компиляции вам нужно знать что-то [A], что вы знаете только во время выполнения.
Комментарии:
1. Это правда, и я понял, «КАК бы я проанализировал что-то во время выполнения, о чем мне НУЖНО знать (во время компиляции)», поэтому я могу также продолжить и дополнить ParserHelper всеми объектами моего домена, которых, к счастью, не так уж много 🙂
Ответ №2:
Во-первых, вам нужно явно передать манифест: я думаю, вы можете, по крайней мере, получить доступ к некоторым Class[_]
( Class.forName
или к чему-либо, основанному на вашем clazz
аргументе). Вы можете создать манифест с помощью ClassManifest.classType(theClass)
. Вы получаете Manifest[_]
.
Тогда вам просто нужно создать процедуру, которая будет принимать Manifest[_]
def parseUntyped(input: String, m: Manifest[_]) = parse(input)(m)
parse(input)(m)
правильно типизированы. Учитывая, что m является манифестом некоторого типа, вызов является правильным. Конечно, возвращаемый тип parseUntyped
is Any
, и вам придется привести его обратно к тому, что вы хотите.
Комментарии:
1. 1 Это работает блестяще, спасибо. Теперь я могу просто добавлять новые классы домена в виде строк в map без необходимости указывать их все в classpath.
Ответ №3:
Сделайте так, чтобы эти классы расширяли признак и использовали этот признак в качестве параметра вашего типа. Помните, что типы в Scala создаются во время компиляции. Притворяясь, что это не так, вы и / или ваш код сойдете с ума.