Преобразование значения в зависимости от типа в SparkSQL через сопоставление типов регистров

можно ли сопоставить параметрический тип в Scala? Допустим у меня есть функция, которая получает два параметра:value и type. Я хотел бы использовать сопоставление шаблонов для преобразования типов.

что-то вроде этого:

datatype match {
  case IntegerType => return value.toInt
  case FloatType => return value.toFloat
  case StringType => return value
  case DecimalType(_,_) => return BigDecimal(value) // this is not working
  case _ => return strrepr
}

здесь DecimalType принимает два параметра для указания точности требуемой точности. Это может быть, например:

org.apache.spark.sql.types.DecimalType = DecimalType(10,2)

Я пробовал несколько вариантов, и ничего не кажется работа:

  • на case DecimalType => return BigDecimal(value) я:

    error: pattern type is incompatible with expected type;
       found   : org.apache.spark.sql.types.DecimalType.type
       required: org.apache.spark.sql.types.DataType
       Note: if you intended to match against the class, try `case DecimalType(_,_)`
    
  • на case DecimalType(_,_) => return BigDecimal(value) я:

    error: result type Boolean of unapply defined in method unapply in object DecimalType does not conform to Option[_] or Boolean
    
  • на case DecimalType[_,_] => return BigDecimal(value) я:

    error: org.apache.spark.sql.types.DecimalType does not take type parameters
    

2 ответов


проблема заключается в использовании return в коде. Вы сказали, что используете этот фрагмент кода в какой-то функции. Что возвращаемый тип этой функции? Очевидно, вы предполагаете, что иногда это целое число, иногда строка, иногда BigDecimal; но если вы используете return, он будет искать тип возвращаемого объекта, чтобы определить возвращаемый тип функции. В общем, вы должны сильно избегать использования return в коде на Scala. Последнее оцененное значение в теле функции возвращенный. Единственный случай использования return - это когда вы хотите принудительно вернуть значение где-то еще в теле функции. Но все же лучшим способом было бы сохранить возвращаемый объект в переменной и просто оценить эту переменную в последней строке тела функции. И никогда не используйте return!

без return он работает

scala> val datatype = DecimalType(10, 2)
datatype: org.apache.spark.sql.types.DecimalType = DecimalType(10,2)

scala> val value = BigDecimal(10)
value: scala.math.BigDecimal = 10

scala> datatype match {case DecimalType(_,_) => value}
res150: scala.math.BigDecimal = 10

** проблемы с возвратом **

scala> def test = {datatype match {case DecimalType(_,_) => return value}}
<console>:138: error: method test has return statement; needs result type
       def test = {datatype match {case DecimalType(_,_) => return value}}

scala> def test:BigDecimal = {datatype match {case DecimalType(_,_) => return value}}
test: BigDecimal

scala> def test:DataType = {datatype match {case DecimalType(_,_) => return value}}
<console>:138: error: type mismatch;
 found   : scala.math.BigDecimal
 required: org.apache.spark.sql.types.DataType
       def test:DataType = {datatype match {case DecimalType(_,_) => return value}}

scala> def test3 = {datatype match {case DecimalType(_,_) => value}}
test3: scala.math.BigDecimal

оказывается, что DecimalType только шаблон соответствует нулевым аргументам:

  case DecimalType() => ...

Если вам нужна точность и масштаб, вы должны определить тип случая и вручную извлечь их:

datatype match {
  case dt: DecimalType =>
    val precision = dt.precision
    val scale = dt.scale
    ...