如果您以 OOP 的眼光审视您所陈述的大多数事实,您或多或少是正确的。但我们对他们还有更多。
对象
从函数式编程的角度来看,Scala 中的对象可以看作是模块。它们确实用于聚合您称为“实用函数”的类似类型的函数。但它们也有其他含义。
object 可以被视为一个单例对象,因为您可以拥有一个继承特定 trait 或 class 的 object。
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 概念非常接近。
性状
在 Scala 中查看trait 的一种方法是使用abstract class。但请注意,您也可以在 Scala 中使用 abstract class,其行为与在 Java 中相同。那么有什么区别呢?
正如评论中指出的,几个traits 可以混在一起。
如果traits 是完全抽象的,也可以认为是Java interface,即所有方法都像Java 一样抽象。事实上,如果您的目标是与 Java 互操作,这就是声明 interface 的方式。
sealed trait 只是一种告诉编译器,除了同一文件中的类或其他特征之外,您不会有任何继承该特征的类或其他特征。正如您在案例类中指出的那样,这用于模式匹配的目的,因此编译器能够通过警告来判断模式匹配是否详尽。但还要注意 Scala 有 enum。
案例分类
案例类可以与sealed trait 一起用于模式匹配。但是case class 更像是一个“价值类”。 case 使编译器生成一堆样板代码,因此您不必这样做。
您有一个自动的“伴随对象”,因此您可以在没有new 的情况下使用自动生成的apply 函数来实例化对象。
您有自动的 hashCode、equals、toString 和 copy 实现。并且所有构造函数的参数都有自动vals。
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)