Estoy tratando de construir una jerarquía de tipos numéricos tipos de dominio. por ejemplo, un Year es un Int (que es un Number), un Percentage es un Double, que es un Number, etc. Necesito la jerarquía, para que yo pueda llamar toInt o toDouble en los valores.

Sin embargo, la Scala tipo de jerarquía para la primitiva tipos numéricos no tiene ningún ancestro común, excepto AnyVal. Este no contiene el to{Int, Double} funciones que necesito.

El tipo más cercano que pude encontrar es Numeric[T], que parece existir principalmente para algunos compilador engaño.

En Java, todos los números derivados de Number (incluyendo la precisión arbitraria queridos). ¿Cómo definir una interfaz que es apto para tipos numéricos de objeto en la Scala?

Actualmente estoy hacking con pato escritura:

Any {
  def toInt: Int
  def toDouble: Double
}

que no sólo es de largo aliento, pero incurre en el tiempo de ejecución de la reflexión de los costos. ¿Hay algo mejor?

  • Lo que es el caso de uso para llamar a toDouble en un Year?
  • hay no… esto es simplemente ilustrativa.
  • Bueno, Numeric typeclass es realmente el camino a seguir, pero Scala todavía utiliza Java Number clase, así que usted puede utilizarlo también.
InformationsquelleAutor fommil | 2013-08-01

2 Comentarios

  1. 50

    Numeric[T] es exactamente lo que usted está buscando. Scala camino a seguir aquí es el tipo de clase (es decir, una cosa como Numeric).

    Lugar de

    def foo(x: java.lang.Number) = x.doubleValue

    escribir uno de

    def foo[T](x: T)(implicit n: Numeric[T]) = n.toDouble(x)
    def foo[T : Numeric](x: T) = implicitly[Numeric[T]].toDouble(x)

    donde el segundo es (casi) nada pero azúcar sintáctico.

    Numérico.Ops

    La escritura llama a la instancia de Numeric cada vez que necesite una operación que puede llegar a ser torpe cuando la expresión es más complejo. Para mitigar esto, Numeric proporciona la conversión implícita mkNumericOps que aumentan T con las formas comunes de la escritura de operaciones matemáticas (es decir, 1 + 2 en lugar de n.plus(1,2)).

    Con el fin de utilizar esos, sólo importar los miembros de la implícita Numeric:

    def foo[T](x: T)(implicit n: Numeric[T]) = {
      import n._
      x.toDouble
    }

    Tenga en cuenta que debido a las restricciones de import la sintaxis abreviada para el implícito es apenas deseable.

    Tipo De Clases

    ¿Qué sucede aquí? Si una lista de argumentos es marcado como implicit, el compilador automáticamente se le puso un valor del tipo requerido no iff exactamente un valor de ese tipo que está marcado como implicit existe en el ámbito. Si usted escribe

    foo(1.0)

    El compilador automáticamente cambiar este

    foo(1.0)(Numeric.DoubleIsFractional)

    proporcionar el método foo con operaciones en Double.

    La enorme ventaja de esto es que usted puede hacer tipos Numeric sin que ellos sepan. Supongamos que usted tiene una biblioteca que le da un tipo de MyBigInt. Supongamos ahora que en el mundo de Java – lamentablemente – los desarrolladores no hacen extender Number. No hay nada que usted puede hacer.

    Scala, sólo se pueden escribir

    implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
       def compare(x: MyBigInt, y: MyBigInt) = ...
       //...
    }

    y todo su código utilizando Numeric ahora funcionará con MyBigInt pero usted no tiene que cambiar la biblioteca. Así Numeric incluso podría ser privado de su proyecto y este patrón todavía funciona.

    • se ha sugerido una edición que explica la magia implícita mejor. Voy a editar el post.
  2. -1

    la respuesta de @gzm0 es una solución estática, que el tipo debe ser comprobado en la compilación de momento, quiero dar una solución dinámica que arrojan el tipo en tiempo de ejecución,

    def toDoubleDynamic(x: Any) = x match {
    case s: String => s.toDouble
    case jn: java.lang.Number => jn.doubleValue()
    case _ => throw new ClassCastException("cannot cast to double")
    }

    Es el caso de uso de partido para elegir el tipo correcto en tiempo de ejecución.

    • Depende de la situación. En mi caso, yo uso scala en la chispa de marco. DataFrame (en la chispa) objeto tiene un campo de tipo numérico distinto, yo no puede conseguir que en tiempo de compilación, pero la mayoría de la chispa de la api requieren doble campo, si no, iba a lanzar excepciones, por lo que la dinámica de la solución funciona en mi aplicación.
    • mi comentario se ha eliminado, no por mí. Me voy a repetir. Esta respuesta es el completo opuesto de la idiomáticas Scala. Si te encuentras queriendo hacerlo de esta manera, usted está utilizando el idioma equivocado o debe pasar algún tiempo para entender el valor de tiempo de compilación a escribir.
    • Pero, todavía sucede. Estoy genera dinámicamente una tabla en HTML y los valores pueden ser absolutamente nada y tengo que seleccionar una clase CSS en función de si es numérico. No es un problema de idioma. Tienes razón en que no debería ser preferido, pero, a veces, es la única manera. Estamos agradecidos por la reflexión y el tiempo de ejecución de escribir.

Dejar respuesta

Please enter your comment!
Please enter your name here