Kotlin Sealed 类

时间:2020-02-23 14:37:32  来源:igfitidea点击:

在本教程中,我们将研究Kotlin Sealed Class。

Kotlin Sealed 类

用外行人的话,顾名思义,密封类是密封的或者封闭的,因此使其受到限制。
密封类用于表示受限的类层次结构,其中对象或者值只能在一种类型中具有值,从而固定了您的类型层次结构。
当您知道给定值仅在给定选项集中意味着什么时,通常使用密封类。

实现Kotlin Sealed 类

Kotlin中的sealed类以以下方式实现。

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类中无法进行以下操作。

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类的此功能?在类似新闻源的应用程序中,您可以为状态,图像和视频帖子创建三种不同的类类型,如下所示。

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

对于Enum类,这是不可能的。

密封类和when

密封类通常与" when"语句一起使用,因为每个子类及其类型都作为一个情况。
此外,我们知道Sealed类会限制类型。
因此," 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<String>) {

  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) //compile-time error.

}

//Following is printed on the console:
//Circle area is 63.585
//Square area is 16
//Rectangle area is 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}")
      }