Kotlin y los sindicatos discriminados (tipos sum)


¿Kotlin tiene algo parecido a los sindicatos discriminados (tipos de suma)? ¿Cuál sería la traducción idiomática Kotlin de este (F#):

type OrderMessage =
    | New of Id: int * Quantity: int
    | Cancel of Id: int

let handleMessage msg = 
    match msg with
        | New(id, qty) -> handleNew id qty
        | Cancel(id) -> handleCxl id
Author: Elias Zamaria, 2015-02-24

3 answers

La forma común de implementar este tipo de abstracción en un lenguaje OO (por ejemplo, Kotlin o Scala) sería a través de la herencia:

open class OrderMessage private () { // private constructor to prevent creating more subclasses outside
    class New(val id: Int, val quantity: Int) : OrderMessage()
    class Cancel(val id: Int) : OrderMessage()
}

Puede empujar la parte común a la superclase, si lo desea:

open class OrderMessage private (val id: Int) { // private constructor to prevent creating more subclasses outside
    class New(id: Int, val quantity: Int) : OrderMessage(id)
    class Cancel(id: Int) : OrderMessage(id)
}

El comprobador de tipos no sabe que dicha jerarquía está cerrada, por lo que cuando se hace una coincidencia de casos (when-expresión) en él, se quejará de que no es exhaustiva, pero esto se arreglará pronto.

Actualización: mientras que Kotlin no es compatible coincidencia de patrones , puede usar cuando - expresiones como moldes inteligentes para obtener casi el mismo comportamiento:

when (message) {
  is New -> println("new $id: $quantity")
  is Cancel -> println("cancel $id")
}

Vea más sobre los moldes inteligentes aquí.

 23
Author: Andrey Breslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-28 07:50:31

Kotlin's sealed class el enfoque de ese problema es extremadamente similar al Scala sealed class y sealed trait.

Ejemplo (tomado del artículo vinculado de Kotlin):

sealed class Expr {
    class Const(val number: Double) : Expr()
    class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}
 23
Author: Adeynack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-16 09:08:58

La clase sellada en Kotlin ha sido diseñada para ser capaz de representar tipos de suma, como sucede con el rasgo sellado en Scala.

Ejemplo:

sealed class OrderStatus {
    object Approved: OrderStatus()
    class Rejected(val reason: String): OrderStatus()
}

El beneficio clave de usar clases selladas entra en juego cuando las usas en una expresión when para la coincidencia.

Si es posible verificar que la instrucción cubre todos los casos, no es necesario agregar una cláusula else a la instrucción.

private fun getOrderNotification(orderStatus:OrderStatus): String{
    return when(orderStatus) {
        is OrderStatus.Approved -> "The order has been approved"
        is OrderStatus.Rejected -> "The order has been rejected. Reason:" + orderStatus.reason
   }
}

Hay varias cosas a tener en mente:

  • En Kotlin al realizar smartcast, lo que significa que en este ejemplo no es necesario realizar la conversión de OrderStatus a OrderStatus.Rechazado para acceder a la propiedad reason.

  • Si no hubiéramos definido qué hacer para el caso rechazado, la compilación fallaría y en el IDE aparece una advertencia como esta:

'cuando' expression debe ser exhaustiva, add necessary 'se rechaza ' branch o' else ' branch en su lugar.

  • cuando se puede utilizar como una expresión o como una declaración. Si se usa como expresión, el valor de la rama satisfecha se convierte en el valor de la expresión general. Si se usa como una instrucción, los valores de las ramas individuales se ignoran. Esto significa que el error de compilación en caso de falta de una rama solo se produce cuando se utiliza como una expresión, utilizando el resultado.

Este es un enlace a mi blog, donde tengo un artículo más completo acerca de ADT con kotlin ejemplos: http://xurxodev.com/tipos-de-datos-algebraicos /

 0
Author: xurxodev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-05 08:56:16