Сопоставление с образцом и (стертый) аргумент универсального типа функции

Допустим, я хочу написать универсальную функцию foo, которая будет использовать сопоставление с образцом, чтобы проверять, относится ли переданный аргумент к типу его универсального аргумента T.

Наивная попытка:

  def foo[T]: PartialFunction[Any, Boolean] = {
    case x: T =>
      true
    case _ =>
      false
  }

... не будет работать, так как T стирается. Предупреждение компилятора подтверждает, что:

Warning:(11, 13) abstract type pattern T is unchecked since it is eliminated by erasure
    case x: T =>
            ^

Как лучше всего заставить его работать?


person Eugene Loy    schedule 06.10.2014    source источник
comment
Обратите внимание, что сопоставление по типу имеет очень мало общего с функциональным программированием, и тот факт, что он не работает в Scala, на самом деле является хорошей вещью (просто позор, что он частично поддерживается и что язык предоставляет обходные пути, такие как ClassTag).   -  person Travis Brown    schedule 06.10.2014
comment
@Travis: вопрос Евгения не был помечен как функциональное программирование, и он не упомянул об этом. Scala — это не только функциональный язык программирования, но и объектно-ориентированный (и даже императивный) язык программирования, так почему бы ему не предоставить обходной путь? Сопоставление типов очень полезно в объектно-ориентированном программировании. Если вам не нужна объектная ориентация, тогда scala — это неправильный язык.   -  person Martin Ring    schedule 07.10.2014
comment
@Martin Моя жалоба не столько о функциональности, сколько о том факте, что Scala смешивает ее с сопоставлением с образцом (что, вероятно, будет первым знакомством многих людей с FP). Если бы у него был свой собственный синтаксис (и он не был бы ужасно сломан дженериками), конечно, это было бы здорово.   -  person Travis Brown    schedule 07.10.2014


Ответы (1)


Scala представила ClassTags для этой цели. Их можно получить с помощью неявного параметра, и они будут предоставлены автоматически, что означает, что вам не нужно беспокоиться о параметре при вызове метода:

import scala.reflect.ClassTag

def foo[T](implicit tag: ClassTag[T]): PartialFunction[Any, Boolean] = {
  case x: T =>
    true
  case _ =>
    false
}

val isString = foo[String] // ClassTag gets provided implicitly here

isString("Hallo") // will return true
isString(42) // will return false

Дополнительные пояснения см. в документах.

person Martin Ring    schedule 06.10.2014