Scala 案例类继承 Product 和 Serializable。

39

我正在学习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))

虽然我知道一个case class是与Product trait混合使用的

我不理解的是:Product with Serializable with Animal

据我所知,Product与模式匹配有关

我已经尝试过谷歌搜索,但没有找到任何内容。请帮忙详细解释概念。

谢谢


嘿,这是一个异构数组,两个元素都扩展自Animal类,因此属于Animal类。如果你将这两个case类放入另一个case类中,然后将该case类添加到数组中,你将得到该case类的数组。 我自己也在寻找关于这个带有Serializable回溯的产品的好读物,但没有找到。也许有人可以澄清我们的想法! - Shivansh
1
http://underscore.io/blog/posts/2015/06/04/more-on-sealed.html - som-snytt
请访问 https://github.com/scala/scala-abide/issues/41。 - som-snytt
@som-snytt:是的,我看到了,但我的问题是编译器为什么这样做,有没有特定的原因。就我所知,签名与模式匹配有关(我可能在这里错了),但我不清楚。 - optional
3个回答

64
这是 case class 的预期行为,因为它的工作原理。case class 自动扩展了两个特质,即 ProductSerializable

Product 特质被扩展,因为 case class 是一种具有 乘积类型代数数据类型

Serializable 特质被扩展,以便将 case class 视为纯数据 - 即可序列化。

DogCat 这样的 case class 不同,你的特质 Animal 没有扩展 ProductSerializable。因此你看到了该类型签名。

当您声明类似于 Array(Dog(""), Cat("")) 这样的内容时,scalac 必须推断出可以表示给定数组所有元素的单个顶级类型

这就是推断类型为 Product with Serializable with Animal 的原因,因为 Animal 没有像 case class 那样隐式扩展 ProductSerializable

要解决此推断问题,您可以使类型显式为 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())

2
感谢您的解释和维基链接,让我清楚了数学模型。 - optional

15

Scala中的所有case类都具有以下几个特性:

  1. 它们将自动扩展Product trait,并为它们提供默认实现,因为它们可以被视为N个记录的笛卡尔积
  2. 它们将扩展Serializable,因为它们可以直接序列化(这是一个设计选择)。
  3. 编译器将为它们提供hashCodeequals的实现,这有助于模式匹配。
  4. 它们将提供applyunapply方法,用于类型的组合和分解。

案例类也是Scala表达代数数据类型的一种方式,更具体地说是积类型元组也是一种积类型,因此它们还扩展了Product特质。

当您使用具有共同特征的两个案例类时,Scala编译器将使用其类型推断算法来尝试找到 ArrayT 类型的最小上界(LUB)。 由于两个案例类通过编译器扩展了ProductSerializable,而trait没有,因此它在搜索期间应用于最终计算的类型。

如果您要避免看到这一点,可以让特质明确地扩展那些特质:

sealed trait Animal extends Product with Serializable

关于这个主题的更多信息可以在这里找到


0
所有的 case class 都会自动扩展 ProductSerializable。看起来很丑?是的。 基本上,Product 可以被视为异构集合。所有的 Product 类(如 Product1、Product2 等)都扩展了 Product,其中包含一些常用的方法,如 productArityproductElement 等。
像 Case classes 一样,其他扩展 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

详情请查看这里


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