Я пишу DSL, и у меня возникла ситуация, когда я хотел бы, чтобы значение было неявно преобразовано в любой тип. Я создал класс-оболочку со значением и неявным методом, который в основном работает:

case class ObjectOperationResult( val value: AnyRef )

object ObjectOperationResult {
    implicit def result2T[ T ]( result: ObjectOperationResult ): T = {
        result.value.asInstanceOf[ T ]
    }
}

Код выдаст исключение, если result.value не является допустимым типом; пользователь должен убедиться, что он поступает правильно. Однако я хотел бы сделать его умнее, выполняя различную логику в зависимости от типа цели. Например, если целевой тип — String, вызовите toString вместо asInstanceOf[]; что-то вроде этого:

case class ObjectOperationResult( val value: AnyRef )

object ObjectOperationResult {
    implicit def result2T[ T ]( result: ObjectOperationResult ): T = {
        match T {
            case String s: result.value.toString
            case _ : result.value.asInstanceOf[ T ]
        }
    }
}

Это не компилируется; есть ли способ определить тип T, чтобы я мог действовать соответственно?

0
DeegC 3 Июл 2015 в 22:51

2 ответа

Вы можете определить несколько функций, например

object ObjectOperationResult {
    implicit def toString( result: ObjectOperationResult ): String =  result.value.toString.trim
    implicit def toInt( result: ObjectOperationResult ): Int = result.value.asInstanceOf[Int]
}

Этот подход лучше по ряду причин:
1. Ваш код будет компилироваться только с правильными типами. Ошибки компиляции всегда лучше, чем ошибки времени выполнения 2. Вы можете вызвать эту функцию явно. Это может быть очень важно, если вы будете вызывать этот код из Java.

-1
Dmitry Meshkov 3 Июл 2015 в 23:18
Это то, что я делаю в настоящее время. Проблема в том, что он не может обрабатывать все возможности. Например, пользователь может захотеть использовать свой собственный класс. Если возможно, мне нужно решение, которое может обрабатывать любой класс.
 – 
DeegC
4 Июл 2015 в 02:36
val str=ObjectOperationResult("foo"); val i=str это будет скомпилировано, поскольку неявное преобразование ObjectOperationResult => Int обеспечивается ObjectOperationResult.toInt, но во время выполнения произойдет сбой из-за приведения anyRefValyeOfStr.asInstanceOf[Int]. Не безопасно во время компиляции.
 – 
cchantep
4 Июл 2015 в 08:17

Один из способов сделать это — передать тип класса в качестве аргумента и условия для него.

import reflect.runtime.universe._

case class ObjectOperationResult( val value: AnyRef )

object ObjectOperationResult {
    def result2T[T: TypeTag](c: Class[T], result: ObjectOperationResult): T = {
        c match {
            case s if typeOf[T] <:< typeOf[String] => result.value.toString.asInstanceOf[T]
            case _ => result.value.asInstanceOf[T]
        }
    }
}

Вот как это можно использовать:

val a = ObjectOperationResult("hello")
val b = ObjectOperationResult(new java.util.Date())

ObjectOperationResult.result2T(classOf[String], a)
res0: String = hello

ObjectOperationResult.result2T(classOf[String], b)
res1: String = Fri Jul 03 13:15:12 PDT 2015

ObjectOperationResult.result2T(classOf[java.util.Date], b)
res2: java.util.Date = Fri Jul 03 13:15:12 PDT 2015
-1
marios 3 Июл 2015 в 23:29