【问题标题】:Scala case class extending Product with SerializableScala 案例类扩展 Product 与 Serializable
【发布时间】:2020-07-17 17:35:26
【问题描述】:

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

虽然我知道案例类与 Product trait 混在一起

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

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

我用谷歌搜索了它,但没有得到任何东西。请帮助我详细了解这个概念。

谢谢

【问题讨论】:

  • 嘿,它是一个异构数组,两个元素都扩展了 Animal,因此使用了 Animal。如果将这两个案例类都放在另一个案例类中,然后将该案例类添加到数组中。你会得到案例类的数组。一段时间以来,我自己正在寻找有关此产品的可序列化的好读物。但没有找到。也许有人可以清除我们的想法。!
  • @som-snytt :是的,我看到了,但我的问题是编译器为什么要这样做,是否有任何具体原因。据我所知,签名正在使用模式匹配(我这里可能有错误),但我不清楚。

标签: scala types traits case-class


【解决方案1】:

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

Product trait 扩展为 case classalgebraic data typeproduct type

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

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

当您声明 Array(Dog(""), Cat("")) 之类的内容时,scalac 需要推断出可以表示给定数组的所有元素的单个 top type

这就是为什么推断的类型是Product with Serializable with Animal,因为Animal 没有扩展Product 也没有扩展Serializable,而case 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())

【讨论】:

  • 感谢您的解释和 wiki 链接,使我对数学模型更加清楚。
【解决方案2】:

Scala 中的所有案例类都具有一些属性:

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

案例类也是 Scala 表达Algebraic Data Type 的方式,更具体地说是Product TypeTuples are also a product type,因此它们也扩展了 Product 特征。

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

如果您想避免看到这种情况,可以让您的 trait 显式扩展这些特征:

sealed trait Animal extends Product with Serializable

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

【讨论】:

    【解决方案3】:

    所有案例类都会自动扩展ProductSerializable。看起来很丑?是的。 基本上,Product 可以看作是异构集合。所有产品类别,即。 (Product1 , Product2 ...) 扩展 Product 包含一些常用方法,如 productArityproductElement 等。

    与 Case 类一样,扩展 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

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 2014-06-30
      • 2019-09-07
      • 2018-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多