何时使用元组而不是案例类

时间:2018-03-01 16:17:22

标签: scala

  

案例类Person(firstName:String,lastName:String)

vs

  

输入Person =(String,String)// firstName,lastName

案例类显然更具可读性。但是,我看到人们使用后者。什么时候使用元组才有意义呢?

作为跟进

是否有性能差异?在一些语言中使用Tuple2就像使用两个原语一样,而创建一个类则会产生开销。但是Scala看起来像Tuple被实现为类。 如果我想要压缩两个sequances的情况怎么样,但更喜欢输出是一个案例类,因为下面提到的所有原因。

例如

`case class UserScores(userId: Long, score: Double)`
users.zip(scores).map{(id ,score) => UserScores(id,score)}

上面的示例需要对集合进行额外的迭代,以及额外的对象创建。 可以使用视图

users.zip(scores).view.map{(id ,score) => UserScores(id,score)}.force

但我不太确定它会产生预期效果

3 个答案:

答案 0 :(得分:9)

当它是最合适的抽象级别时,你应该使用元组。

例如,如果你正在编写一个框架,其中一切都是完全通用的,你可以得到的最具体的东西是“函数”,“笛卡尔积”,“半群”或类似“封闭的幺半群类”,那么你可能别无选择,只能使用Tuple。这是一个很好的例子:Semigroupal方法:

 product[A, B](fa: F[A], fb: F[B]): F[(A, B)]

这里,元组类型的使用是完全合理的,因为接口足够抽象。

另一个例子:在整个Scala collection library中,你永远不会遇到像Person(name: String, surname: String)这样具体的东西,但是你会看到很多方法都在泛型类型的元组上工作{{1} }。

但是,如果代码中最抽象的东西是

(A, B)

然后你突然发现你还需要object Fred { val name = "Fred" val surname = "Bloggs" } 的另一个类似对象,定义

更合适
John Doe

然后甚至可能像这样使用它:

case class Person(name: String, surname: String)

当然,准确建模域名具有重要价值。这两个目标 - 准确地建模具体领域与编写在尽可能多的情况下工作的通用框架 - 是互补的。

总结:

  • 你在编写一个足够抽象的完全通用的框架吗?使用元组。
  • 您是否尝试尽可能地模拟某些具体领域?使用适当命名的案例类。

这里:

val j = Person(name = "John", surname = "Doe")

看起来像域和使用的抽象之间的不匹配。您可以简单地从编译器不会阻止您意外地交换这两个组件的事实看到它。相反,如果您使用通用type Person = (String, String) //firstName, lastName A类型在不同的抽象级别工作,如果您不小心交换了B (B, A),编译器会发出错误消息预期

答案 1 :(得分:4)

恕我直言,作为一般规则:

  • 默认情况下,您应该更喜欢案例类:它不会花费更多,而且更清晰
  • 此外,case类提供了许多实用的功能,例如apply,unapply和copy (来自评论:元组也有那些)
  • 长度的元组>一般应避免使用3

可是:

  • 对于具有多个输出的方法,通常会立即拆分。然后使用元组
  • 在几种算法中,特别是使用功能映射/ flatMap / etc ...,你有很多中间的“单行”结果,你不需要定义一个案例类。
  • 最后,如andrey-tyukin所述,如果您编写通用类型算法,则可能更喜欢元组。但是,你可以使用无形魔法实际上做一些很好的通用案例类代码

关于类型别名的最后一条评论:当我不想创建类时,我主要使用它们来提高可读性。这种情况发生在两种情况下:

  • 别名类型是一个原语,如Int或Double,在关键代码中使用,我想避免装箱(注意这需要尊重其他约束才有效)。
  • 当单个类型具有多种含义但创建案例类时会过度设计。防爆。说几个API使用param: Map[String, Double]。 Map是一个很好的类型,你不想把它包装在一个类中。然后,可能更具可读性,在您的代码ApiParams
  • 中有type ApiParams = Map[String, Double]

答案 2 :(得分:1)

也许如果订单无关紧要。因此,与firstName / lastName示例不同,它有区别。

仍然没有可用的信息,值是什么,但在一般情况下,可能没有信息。