Kotlin 封闭类

在本教程中,我们将深入研究 Kotlin 密封类。它们是什么?它们有什么用途?我们将在下面解决所有这些问题。

Kotlin 密封类

简单来说,顾名思义,密封类是密封或封闭的,因此受限制。密封类用于表示受限制的类层次结构,其中对象或值只能在类型中的一种之间具有值,从而固定了类型层次结构。密封类通常用于在您知道给定值仅在给定选项集合之间时使用。

实现 Kotlin 密封类

在 Kotlin 中,密封类是以下方式实现的。

sealed class A{
    class B : A()
    class C : A()
}

要指定密封类,您需要添加修饰符 sealed。密封类不能被实例化。因此,它们隐式地是抽象的。以下方式是行不通的。

fun main(args: Array<String>) 
{
    var a = A() //compiler error. Class A cannot be instantiated.
}

密封类的构造函数默认为私有。密封类的所有子类必须在同一文件中声明。密封类在编译时通过限制类型集合来确保类型安全

sealed class A{
    class B : A() 
    {
        class E : A() //this works.
    }
    class C : A()

    init {
        println("sealed class A")
    }

}

class D : A() //this works
{
class F: A() //This won't work. Since sealed class is defined in another scope.
}

使用構造函數創建封閉類。

sealed class A(var name: String){
    class B : A("B")
    class C : A("C")
}

class D : A("D")
fun main(args: Array<String>) {
    
    var b = A.B()
    var d = D()
}

在封閉類中添加 數據類對象

fun main(args: Array<String>) {

    val e = A.E("Anupam")
    println(e) //prints E(name=Anupam)

    var d = A.D
    d.name() //prints Object D
}


sealed class A{
    class B : A()
    class C : A()
    object D : A()
    {
         fun name()
         {
             println("Object D")
         }
    }
    data class E(var name: String) : A()

}

枚舉和封閉類的區別

在 Kotlin 中,封閉類可以被稱為增強版的枚舉類。封閉類允許我們創建具有不同類型的實例,而不像 枚舉 那樣限制我們對所有枚舉常量使用相同類型。在枚舉類中無法實現以下功能。

enum class Months(string: String){
January("Jan"), February(2),
}

枚舉類僅允許所有常量使用單一類型。這就是封閉類通過允許多個實例來幫助我們的地方。

sealed class Months {
    class January(var shortHand: String) : Months()
    class February(var number: Int) : Months()
    class March(var shortHand: String, var number: Int) : Months()
}

您如何在項目中使用封閉類的此功能?在類似新聞稿的應用程序中,您可以像下面所示為狀態、圖像、視頻帖子創建三種不同的類型。

sealed class Post
{
    class Status(var text: String) : Post()
    class Image(var url: String, var caption: String) : Post()
    class Video(var url: String, var timeDuration: Int, var encoding: String): Post()
}

這在枚舉類中是不可能的。

封閉類和 when

封裝類別通常與 when 語句一起使用,因為每個子類別及其類型都充當一個情況。此外,我們知道封裝類別限制了類型。因此, when 語句的 else 部分可以很容易地移除。以下示例演示了相同的情況。

sealed class Shape{
    class Circle(var radius: Float): Shape()
    class Square(var length: Int): Shape()
    class Rectangle(var length: Int, var breadth: Int): Shape()
}

fun eval(e: Shape) =
        when (e) {
            is Shape.Circle -> println("Circle area is ${3.14*e.radius*e.radius}")
            is Shape.Square -> println("Square area is ${e.length*e.length}")
            is Shape.Rectangle -> println("Rectagle area is ${e.length*e.breadth}")
        }

讓我們按照以下所示在我們的 main 函式中執行 eval 函式。

fun main(args: Array) {

    var circle = Shape.Circle(4.5f)
    var square = Shape.Square(4)
    var rectangle = Shape.Rectangle(4,5)

    eval(circle)
    eval(square)
    eval(rectangle)
    //eval(x) //編譯時錯誤。

}

//以下內容會被列印在控制台上:
//圓形面積為 63.585
//正方形面積為 16
//矩形面積為 20

注意: is 修飾符檢查類別是否為以下類型。 is 修飾符僅對類別需要,對於 Kotlin 物件不需要,如下所示:

sealed class Shape{
    class Circle(var radius: Float): Shape()
    class Square(var length: Int): Shape()
    object Rectangle: Shape()
    {
        var length: Int = 0
        var breadth : Int = 0
    }
}

fun eval(e: Shape) =
        when (e) {
            is Shape.Circle -> println("Circle area is ${3.14*e.radius*e.radius}")
            is Shape.Square -> println("Square area is ${e.length*e.length}")
            Shape.Rectangle -> println("Rectangle area is ${Shape.Rectangle.length*Shape.Rectangle.breadth}")
        }

這就結束了 Kotlin 封裝類別教程。參考資料: Kotlin 文件

Source:
https://www.digitalocean.com/community/tutorials/kotlin-sealed-class