Проверить, доступно ли неявное преобразование

#scala #implicit-conversion

#scala #неявное преобразование

Вопрос:

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

 if (x can-be-converted-to SomeType)
  return something(conversion(x))
else
  return someotherthing(x)
  

Например, x является значением Int и должно быть преобразовано в RichInt.
Возможно ли это в Scala? Если да, то каким образом?

Спасибо

Комментарии:

1. неявные преобразования существуют только во время компиляции, а не во время выполнения. Если вы хотите проверить, существует ли такое преобразование, вы можете записать код и попытаться его скомпилировать. Компилятор сообщит вам, можно ли его скомпилировать.

Ответ №1:

Как уже упоминалось ранее, имплициты разрешаются во время компиляции, поэтому, возможно, вам лучше использовать классы типов для решения подобных проблем. Таким образом, у вас есть преимущество в том, что позже вы сможете расширить функциональность до других типов.

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

Решение Жана-Филиппа, использующее аргумент по умолчанию, уже довольно хорошее, но null может быть устранено, если вы определите синглтон, который можно поместить вместо неявного параметра. Сделайте это закрытым, потому что на самом деле это бесполезно в другом коде и может быть даже опасно, поскольку неявные преобразования могут происходить неявно.

 private case object NoConversion extends (Any => Nothing) {
   def apply(x: Any) = sys.error("No conversion")
}

// Just for convenience so NoConversion does not escape the scope.
private def noConversion: Any => Nothing = NoConversion

// and now some convenience methods that can be safely exposed:

def canConvert[A,B]()(implicit f: A => B = noConversion) =
  (f ne NoConversion)

def tryConvert[A,B](a: A)(implicit f: A => B = noConversion): Either[A,B] = 
  if (f eq NoConversion) Left(a) else Right(f(a))

def optConvert[A,B](a: A)(implicit f: A => B = noConversion): Option[B] =
  if (f ne NoConversion) Some(f(a)) else None
  

Комментарии:

1. Спасибо за этот ответ. При тестировании, например, с помощью «canConvert[Boolean, Упорядоченный[логическое значение]]», он возвращает false . Я думал, что будет использоваться преобразование в RichBoolean, но, похоже, нет. Что не так?

2. Без кода мне придется догадываться: вероятно, вы вызвали это со скобками вот так: canConvert[Boolean,Ordered[Boolean]]() . Затем компилятор заполняет параметр по умолчанию, который не является тем, что вы хотите. Либо удалите скобки из вызова, либо добавьте пустой список параметров перед неявными параметрами.

3. @saucisson Я обновил код, включив в него пустой список параметров — теперь не имеет значения, вызываете ли вы canConvert метод с пустым списком параметров или без него.

Ответ №2:

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

 def toB[A](a: A)(implicit convertFct: A => B = null) =
  if (convertFct != null)
    convertFct(a)
  else
    someOtherThing(a)
  

Обратите внимание, что мне кажется любопытным проверить это во время выполнения, потому что компилятор знает во время компиляции, доступна ли такая функция преобразования.