12

Вопрос по generics – Как вернуть null из универсальной функции в Scala?

Я пишу свой простойjavax.sql.DataSource реализация, единственный способ этого мне нужно работатьgetConnection: Connection, но интерфейс наследует многие другие методы (которые мне не нужны) отjavax.sql.CommonDataSource а такжеjava.sql.Wrapper, Итак, я бы хотел "внедрить" эти ненужные методы, которые они на самом деле не будут работать, но будут вести себя адекватно при вызове. Например я реализуюboolean isWrapperFor(Class<?> iface) как

def isWrapperFor(iface: Class[_]): Boolean = false

и я хотел бы реализовать<T> T unwrap(Class<T> iface) как

def unwrap[T](iface: Class[T]): T = null

Но последнее не работает: компилятор сообщает о несоответствии типов.

Будет ли правильно использоватьnull.asInstanceOf[T] или есть лучший способ? Конечно, я считаю, просто бросатьUnsupportedOperationException вместо этого в данном конкретном случае, но ИМХО вопрос все еще может быть интересным.

  • Это правда, я не знал, что это не работает с функциями, что, кстати, грустно. Спасибо за исправление

    от
  • В 2.9.1 это даетerror: unbound placeholder parameter

    от
  • Ты можешь использоватьAnyRef, но тогда вы должны броситьnull вT, Также я думаю, что более просто сказать, что этот тип должен быть обнуляемым вместо того, чтобы говорить, что это должен быть ссылочный тип.

    от
  • Я не имел дело сisWrapperFor/unwrap на практике, но предположим, чтоunwrap равно нулю в случаеisWrapperFor равно ложь и реализацииisWrapperFor как= null кажется наиболее адекватным в том случае, если объект никогда не может быть оберткой. Разве я не прав?

    от Ivan
  • Не новость, что в Scala есть ненулевые типы ... Я подумалInt обнуляется в отличие от примитива Javaint...

    от Ivan
  • Int имеет тип AnyVal, а типы значений не могут быть обнуляемыми.

    от
  • Def ??? = throw new UnsupportedOperationException // очень легко добавить в Scala & lt; 2,10

    от
  • Это помогло мне (попытка написать помощника, который бы облегчил вызов библиотеки Java). Как примечание вы знаете, почему вы не можете использовать верхнюю границу AnyRef? Я думал, что Null подтип всех ссылочных классов?

    от
  • хотя @oxbow_lakes упоминает, что бросание предпочтительнее, чем возвращение нулевого значения в большинстве случаев

    от
  • 16

    Это потому что

    T может быть необнуляемым типом. Это работает, когда вы применяетеT быть обнуляемым типом:

    def unwrap[T >: Null](iface: Class[T]): T = null
    
    unwrap(classOf[String]) // compiles
    
    unwrap(classOf[Int]) // does not compile, because Int is not nullable
    

  • 6

    Вот так: def unwrap[T](iface: Class[T]): T = sys

    & Quot; правильно & quot; Решение состоит в том, чтобы сделать что-то, что будетimmediately потерпеть поражение. Вот так:

    def unwrap[T](iface: Class[T]): T = sys.error("unimplemented")
    

    В скале2.10, это было бы реализовано как:

    def unwrap[T](iface: Class[T]): T = ???
    

    Потому что есть новый метод вPredef называется???, Это работает, потому что выражение формыthrow new Exception имеет типNothing, который является подтипом любого типа (он называетсяbottom в теоретико-типовых кругах).

    Причина в том, что этоcorrect является то, что гораздо лучше сразу потерпеть неудачу с ошибкой, чем использоватьnull который может потерпеть неудачу позже и скрыть причину.

  • 1

    As said in comments, this solution doesn't work

    Если я хорошо понял вашу проблему, вы также можете назначить значения по умолчанию, как подробно описано вчто значит назначить & quot; _ & quot; в поле в скале?, Вы можете найти больше информации в4.2 Variable Declarations and Definitions изThe Scala Language Specification

    Так что вы можете просто сделать:

    def unwrap[T](iface: Class[T]): T = _
    

    который установитunwrap сnull без несоответствия типов.