Scala 案例 class 使用 Serializable 扩展 Product

Scala case class extending Product with Serializable

我正在学习 Scala 并尝试遵循 Scala Cookbook 的形式:

trait Animal
trait FurryAnimal extends Animal
case class Dog(name:String) extends Animal
case class Cat(name:String) extends Animal

现在当我按照 :

val x = Array(Dog("Fido"),Cat("Felix"))

结果显示为:

x:Array[Product with Serializable with Animal] = Array(Dog(Fido),Cat(Felix))

虽然我知道有一个案例class混入了Product trait

我没有得到的是:Product with Serializable with Animal

据我了解产品与模式匹配有关

我做到了 google 但没有理解 anything.Please 帮助我详细了解概念。

谢谢

Scala 中的所有情况 类 都具有一些属性:

  1. 它们将自动扩展 Product 特性,并为它们提供默认实现,因为它们可以被视为 a Cartesian Product of N records
  2. 它们将扩展 Serializable,因为它们是开箱即用的可序列化(作为设计选择)。
  3. 他们将有编译器提供的 hashCodeequals 的实现,这有助于模式匹配
  4. 他们将提供 applyunapply 方法,用于类型的组合和分解。

大小写 类 也是 Scala 表达 Algebraic Data Type, more specifically a Product Type. Tuples are also a product type 的方式,因此它们也扩展了 Product 特征。

当您使用具有共同特征的两个 case 类 时,scala 的编译器将使用它的类型推断算法来尝试找到 T 类型的最小上限 (LUB) Array。由于两种情况 类 都通过编译器扩展了 ProductSerializable,而 trait 没有,它将在搜索期间将其应用于最终计算类型。

如果你想避免看到这些,你可以让你的特征显式地扩展这些特征:

sealed trait Animal extends Product with Serializable

可以找到关于此主题的更多信息here

所有大小写 类 自动扩展 ProductSerializable。长得丑吗?是的。 基本上,Product 可以看作是异构集合。所有产品 类 即(Product1 , Product2 ...) extends Product 其中包含一些常用方法,例如 productArity , productElement

像大小写 类 扩展 Product 的其他类型有 ListTuple

来自我的 Scala 工作表,

  val product : Product = (10,"String",3)         //> product  : Product = (10,String,3)
  product.productArity                            //> res0: Int = 3
  product.productElement(0)                       //> res1: Any = 10
  product.productElement(1)                       //> res2: Any = String
  product.productElement(2)                       //> res3: Any = 3

case class ProductCase(age:Int,name:String,ISBN:Int)
  ProductCase(23,"som",5465473).productArity      //> res4: Int = 3

详情请看here

由于 case class 的工作方式,这是预期的行为。 case class自动extends两个trait,即ProductSerializable

Product 特性被扩展为 case class 是一个 algebraic data type with product type.

Serializable 特性得到扩展,因此 case class 可以被视为纯数据 - 即能够被序列化。

case class DogCat 不同,您的特征 Animal 不会扩展 ProductSerializable。因此,您会看到类型签名。

当你声明类似 Array(Dog(""), Cat("")) 的东西时,scalac 需要推断单个 top type 可以表示给定数组的所有元素。

这就是推断类型为 Product with Serializable with Animal 的原因,因为 Animal 没有扩展 Product 也没有扩展 Serializablecase class 隐式扩展了。

要解决此推断,您可以通过 Animal 明确类型或使 Animal 扩展 ProductSerializable.

trait Animal extends Product with Serializable

case class Dog(name: String) extends Animal
case class Cat(name: String) extends Animal

Array(Dog(""), Cat("")) // Array[Animal] = Array(Dog(), Cat())