LINUX.ORG.RU

Возможно ли в scala/другом яп динамически менять тип возвращаемого значения?

 ,


0

2

Как то так:

public class Parent {}
public class ChildA extends Parent {}
public class ChildB extends Parent {}

public class Test
{
  public static <T extends Parent> T test()
  {
    if(T.getClass() == ChildA.class)
      return new ChildA();
    else
    if(T.getClass() == ChildB.class)
      return new ChildB();

    else throw new Exception("123");
  }
}

ChildA a0 = Test.<ChildA>test(); //Ok
ChildA a1 = Test.<ChildB>test(); //Fail



Последнее исправление: koi8-r (всего исправлений: 1)

Возможно, в scala есть class tag. В твоем примере на java можно тоже, если T сделать аргументом класса и создавать вот так: new Test<ChildA>(){}.test();

dizza ★★★★★
()
Ответ на: комментарий от dizza

В Java нельзя создать класс по его generic типу, нужно передавать объект Class<T> в метод test. В Scala в принципе всё точно так же, только можно передавать этот объект неявно.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)

Не джавист, потому спрошу. А в чём суть-то? Просто return new T() нельзя было написать?

yoghurt ★★★★★
()
import scala.reflect.runtime.universe._

trait Parent
class ClazzB extends Parent{}
class ClazzA extends Parent{}

object ReifyTest extends App{
  def genericFactory[T <: Parent](implicit tt: TypeTag[T]):Parent =
    tt.tpe match {
      case t if t == typeOf[ClazzA] => new ClazzA
      case t if t == typeOf[ClazzB] => new ClazzB
    }

  println(genericFactory[ClazzB].getClass)
  println(genericFactory[ClazzA].getClass)
}
RedPossum ★★★★★
()
Ответ на: комментарий от RedPossum

даже так:

import scala.reflect.ClassTag

trait Parent
class ClazzB extends Parent{}
class ClazzA extends Parent{}

object ReifyTest extends App{
  def genericFactory[T <: Parent](implicit tt: ClassTag[T]):T =
    tt.runtimeClass.newInstance.asInstanceOf[T]

  println(genericFactory[ClazzB].getClass)
  println(genericFactory[ClazzA].getClass)
}

RedPossum ★★★★★
()
Ответ на: комментарий от RedPossum

или так, чертова scala, всегда можно что-то подправить

def genericFactory[T](implicit tt: ClassTag[T]):T =
    tt.runtimeClass.newInstance.asInstanceOf[T]

def clazzGenericFactory[T <: Parent](implicit tt: ClassTag[T]) = genericFactory[T]
RedPossum ★★★★★
()
Последнее исправление: RedPossum (всего исправлений: 2)
Ответ на: комментарий от yoghurt

Просто return new T() нельзя было написать?

Нельзя. Дженерики в жабе появились поздно, виртуальная машина уже была, корёжить её не хотелось, делать манглинг тоже. Сделали стирание типов. То есть, внутри дженерика test тип T неизвестен, и что именно конструировать никто не знает. Если есть объект этого типа, то можно дёрнуть его метод, а вот создать объект с нуля - никак.

Miguel ★★★★★
()
Ответ на: комментарий от Debasher

А вообще ты хочешь странного

Ему ЯП не дает ногу отстрелить, а ему очень хочется. Суицидальные наклонности на лицо.
ЗЫ. Ващето к психитору надо а не на форум :)

vada ★★★★★
()
Ответ на: комментарий от yoghurt

Кстати, это можно делать в .net. Там стирания типов нет, соответственно, new T() вполне прокатывает.

Miguel ★★★★★
()
Ответ на: комментарий от Debasher

Хотел сделать как то так:

UserModel u = DAOFabric.<UserModel>createDAO().sqlSelectAndParse();
DocumentModel d = DAOFabric.<DocumentModel>createDAO().sqlSelectAndParse();
Но уже далаю так:
UserModel u = new UserDAO().sqlSelectAndParse();
DocumenModel u = new DocumenDAO().sqlSelectAndParse();

koi8-r
() автор топика
Ответ на: комментарий от Legioner

Это понятно, но можно вытащить тип:

    public static class Parent {}
    public static class ChildA extends Parent {}
    public static class ChildB extends Parent {}

    public static class Factory<T extends Parent> {
        public T create() {
            Class<T> clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            try {
                return clazz.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(new Factory<ChildA>(){}.create());
        System.out.println(new Factory<ChildB>(){}.create());
    }
dizza ★★★★★
()
Ответ на: комментарий от dizza

господа, вы здесь славно упражняетесь в костылестроении, но рефлексия как тормозила, так и тормозит. проще по фабрике на тип создать руками, чем каждый раз мало того, что рефлексия, так еще и новый объект.

но это не вы, это джава. я тоже от этого страдаю.

скастуйте биореактора, пусть посоветует, как в Ънтерпрайзе делают.

anonymous
()
Ответ на: комментарий от anonymous

Да понятное дело все это упражнения для ума. Правильное продакшен решение, это юзать DI, создавая в контексте UserDAO и DocumentDAO, и иньектя их там, где это нужно без всяких фабрик.

dizza ★★★★★
()

Если возикает такая задача, обычно это означает что что-то где-то пошло не так.

ya-betmen ★★★★★
()
Ответ на: комментарий от dizza
@Inject private GenericDAO<DocumentModel> dDao;
@Inject private GenericDAO<UserModel> uDao;

Отлично, то что нужно и работает.

koi8-r
() автор топика
Ответ на: комментарий от Miguel

Ну, если очень сильно хочется, то как. Но с очень большим геммороем и костылями. Через через reflection из generic type, выгрызаем класс параметра (довольно просто делается с помощью commons lang, хотя можно и самому написать), после чего делаем newInstance и каст к нужному типу.

Nagwal ★★★★
()
Ответ на: комментарий от Nagwal

через reflection из generic type, выгрызаем класс параметра

Э-э-э? А можно с этого места поподробнее? Я до сих пор был уверен, что это просто невозможно.

Miguel ★★★★★
()
Ответ на: комментарий от Nagwal

На этом например все ORM-ы построены, когда определяют тип коллекции, не используя дополнительных аннотаций.

Nagwal ★★★★
()
Ответ на: комментарий от anonymous

Тип дженерика сохраняется при подстановке в подклассах. Мало кто про это знает. См. мой пример.

dizza ★★★★★
()
Ответ на: комментарий от vada

Разработчики jersey тоже.

package javax.ws.rs.client.SyncInvoker
T get(java.lang.Class<T> responseType)

koi8-r
() автор топика
Ответ на: комментарий от dizza

Можете обьяснить как это работает (метод get), исходники читал, но ничего не разобрал. Передаем String.class и получаем только T == String, передаем Response.class и получаем только T == Response

cast Miguel

public class JerseyClientTest
{
    @Test
    public void run() throws Exception
    {
        /*
        package javax.ws.rs.client.SyncInvoker
        <T> T get(java.lang.Class<T> responseType)
         */
        Client client = ClientBuilder.newClient();
        String r = client.target("http://localhost:8080/api/v0.1/sandbox/hello").request("text/plain").get(String.class);
        assertEquals(r, "Hello, World!");
    }
}
koi8-r
() автор топика
Ответ на: комментарий от koi8-r

Если пройти по сорцам, то суть своидтся к такому:

T t = (T) workers.readFrom(
                    rawType, // объявлен как Class<T> rawType
                    type,
                    annotations,
                    mediaType,
                    headers,
                    propertiesDelegate,
                    entityContent.getWrappedStream(),
                    entityContent.hasContent() ? getReaderInterceptors() : Collections.<ReaderInterceptor>emptyList(),
                    translateNce);
Где у readFrom сигнатура с вайлдкардом:
public Object readFrom(Class<?> rawType, //...

Или к такому:

if (responseType == Response.class) {
            return responseType.cast(new InboundJaxrsResponse(response, scope));
        }

anonymous
()
Ответ на: комментарий от anonymous

Отлично, разобрался. Жаль приходиться юзать

@SuppressWarnings("unchecked")

koi8-r
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.