web-dev-qa-db-ja.com

Kotlinと差別化された労働組合(合計タイプ)

Kotlinには、差別化された労働組合(合計型)などがありますか?これの慣用的なKotlin変換は何でしょうか(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
41
ehnmark

この種の抽象化をOO言語(KotlinやScalaなど)で実装する一般的な方法は、継承によるものです。

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()
}

必要に応じて、共通部分をスーパークラスにプッシュできます。

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)
}

型チェッカーは、そのような階層が閉じていることを認識していません。そのため、大文字と小文字のような一致(when- expression)を実行すると、完全ではないというメッセージが表示されますが、これは修正されますすぐに。

Update:Kotlinはパターンマッチングをサポートしていませんが、when-式をスマートキャストとして使用すると、ほぼ同じ動作が得られます。

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

スマートキャストについての詳細 ここ を参照してください。

33
Andrey Breslav

Kotlinのsealed class その問題へのアプローチは Scala sealed classおよびsealed trait

例(リンクされたKotlinの記事から引用):

sealed class Expr {
    class Const(val number: Double) : Expr()
    class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}
35
Adeynack

Kotlinの封印されたクラスは、Scalaの封印された特性で発生するように、合計型を表すことができるように設計されています。

例:

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

シールされたクラスを使用することの主な利点は、マッチのwhen式でクラスを使用するときに役立ちます。

ステートメントがすべてのケースをカバーしていることを確認できる場合は、ステートメントにelse句を追加する必要はありません。

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
   }
}

覚えておくべきことがいくつかあります。

  • Kotlinでスマートキャストを実行する場合。つまり、この例では、理由プロパティにアクセスするためにOrderStatusからOrderStatus.Rejectedへの変換を実行する必要はありません。

  • 拒否された場合の対処方法を定義していない場合、コンパイルは失敗し、IDEには次のような警告が表示されます。

'when'式は完全でなければならないので、代わりに必要な 'is Rejected'ブランチまたは 'else'ブランチを追加してください。

  • 式またはステートメントとして使用できる場合。式として使用した場合、満たされた分岐の値が一般式の値になります。ステートメントとして使用した場合、個々のブランチの値は無視されます。これは、分岐がない場合のコンパイルエラーは、結果を使用して式として使用された場合にのみ発生することを意味します。

これは私のブログ(スペイン語)へのリンクです。ここには、ADTに関するKotlinの例を含むより完全な記事があります。 http://xurxodev.com/tipos-de-datos-algebraicos/

5
xurxodev