superior - kotlin tutorial español pdf
Kotlin y uniones discriminadas(tipos de suma) (3)
¿Tiene Kotlin algo así como uniones discriminadas (tipos de suma)? ¿Cuál sería la traducción idiomática de Kotlin de esto (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
La clase sellada en Kotlin ha sido diseñada para poder 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 el partido.
Si es posible verificar que la declaración cubra todos los casos, no es necesario que agregue una cláusula else a la declaració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 cuenta:
En Kotlin al realizar una difusión inteligente, lo que significa que en este ejemplo no es necesario realizar la conversión de OrderStatus a OrderStatus.Rejected para acceder a la propiedad de motivo.
Si no hubiéramos definido qué hacer para el caso rechazado, la compilación fallaría y en el IDE aparecerá una advertencia como esta:
''cuando'' la expresión debe ser exhaustiva, agregar necesario ''es Rechazada'' rama o ''else'' rama en su lugar.
- cuando se puede utilizar como una expresión o como una declaración. Si se utiliza como una expresión, el valor de la rama satisfecha se convierte en el valor de la expresión general. Si se utiliza como una declaración, los valores de las ramas individuales se ignoran. Esto significa que el error de compilación en caso de que falte una rama solo ocurre cuando se usa como una expresión, usando el resultado.
Este es un enlace a mi blog (español), donde tengo un artículo más completo sobre ADT con ejemplos de kotlin: http://xurxodev.com/tipos-de-datos-algebraicos/
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 verificador de tipos no sabe que dicha jerarquía está cerrada, por lo que cuando haga una coincidencia de tipo mayúscula ( when
-expresión) en ella, se quejará de que no es exhaustiva, pero esto se solucionará pronto.
Actualización: aunque Kotlin no admite la coincidencia de patrones , puede usar when -expressions como Smart Cast para obtener casi el mismo comportamiento:
when (message) {
is New -> println("new $id: $quantity")
is Cancel -> println("cancel $id")
}
Ver más sobre los moldes inteligentes here .
El enfoque de sealed class
de Kotlin para ese problema es extremadamente similar a la sealed class
Scala y el sealed trait
.
Ejemplo (tomado del artículo de Kotlin vinculado):
sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}