Scala中的Class、Object、Trait和Sealed Trait

15
我来自面向对象编程(OOP)背景,希望清楚地了解Scala中的Object、Classes、Trait、Sealed Trait和Case Classes。以下是我目前所理解的内容:
我们创建 Object,当我们想要在其中编写一些实用程序函数并可以直接访问它,而无需像Java中的“Static”类那样使用“new”关键字。
我们创建 Classes,当我们编写动词意味着一个对象及其行为封装同样类似于我们在Java中编写类时,并使用“new”关键字对其进行实例化。
我们创建 Trait,当我们想要编写与Java中的抽象类相同的代码时。
我们创建 Sealed Trait,当我们想要实现与Java中Enum相同的功能时。
我们创建 Case classes,当我们期望该类可用于将来的模式匹配,类似于Java中的instanceOf。
我的理解是否正确?

仅针对“Trait”进行评论:由于您的类可以继承多个Trait(混入),因此我不会将其与Java抽象类进行比较。 - GhostCat
你的意思是说,我们可以在类中扩展多个Trait,但Java限制我们一次只能扩展一个类?如果是这样,还有其他区别吗? - Arpit Aggarwal
是的,您可以扩展任意数量的特质。 - Diego Martinoia
1个回答

21

如果你从面向对象编程的角度看待它们,那么你所陈述的大多数事实基本上是正确的。但是我们还有更多东西需要探讨。

对象

在Scala中,对象可以被视为模块,从函数式编程的角度来看。它们确实用于聚合你所称之为“实用函数”的类似函数。但是它们还具有其他含义。

object可以被视为单例对象,因为你可以拥有一个继承特定traitclassobject

trait Bird
object Duck extends Bird

你还有伴生对象的概念。它是一个具有与该类相关模块函数的对象,您甚至可以从类中引用private成员。

class Dog {
  def eat(food: Food) = Dog.preferredFoods.contains(food)
}

object Dog {
  private val preferredFoods = List(Ribeye, DogFood, Banana)
  def walk(dog: Dog) = ???
}

你对类的理解是正确的。它们与Java的概念密切相关。

Trait

在Scala中,将trait视为abstract class的一种方式。但请注意,你也可以在Scala中拥有一个abstract class,其行为与Java中相同。那么它们的区别是什么呢?

正如评论中指出的那样,可以将多个trait混合在一起。此外,如果一个trait完全是抽象的,即所有方法都像Java中的抽象类一样都是抽象的,那么trait也可以被看作是一个Java的interface。实际上,如果你的目标是与Java进行交互操作,这是声明interface的方式。

sealed trait只是告诉编译器,除了与之同文件中的其他类或特质以外,你不会有任何其他继承该类的情况。这有助于模式匹配,就像case类一样。因此编译器能够发出警告,告诉您模式匹配是否穷尽。但是请注意,Scala还有enum

Case类

可以将case类与sealed trait一起使用来进行模式匹配。但case class更像是一个“值类”。“case”使编译器生成大量样板代码,因此你不必自己写。

你可以拥有自动的“伴生对象”,因此你可以在没有new关键字的情况下实例化该对象,并使用自动生成的apply函数。

你还可以自动获得hashCodeequalstoStringcopy实现。并且对于所有构造函数的参数,你都可以自动获得val

scala> case class Room(area: Int)
defined class Room

scala> var r = Room(16)
r: Room = Room(16)

scala> r.hashCode
res2: Int = 1313771839

scala> r == Room(16)
res3: Boolean = true

scala> r == Room(15)
res4: Boolean = false

scala> r.toString
res5: String = Room(16)

scala> r.area
res6: Int = 16

scala> case class Point(x: Int, y: Int)
defined class Point

scala> val p = Point(1, 1)
p: Point = Point(1,1)

scala> val p1 = p.copy(y = 0)
p1: Point = Point(1,0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接