在 Scala 中将所有类定义为 case 以便让它们的所有参数自动成为属性是否正确?

发布于 2024-09-16 07:36:50 字数 69 浏览 1 评论 0原文

我开始使用Scala。如果我希望将一个类的参数公开为属性,我应该将其定义为案例类,我的理解是否正确?它不会带来任何副作用吗?

I'm beginning Scala. Am I correct understanding that I should define a class as a case class if I'd like it's arguments to be exposed as properties? Does not it introduce any side effects?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

晨曦÷微暖 2024-09-23 07:36:50

为案例类生成的样板代码在字节码中具有较小但非零的成本。除了copy方法之外,还有hashCodeequalstoString以及伴随对象工厂方法。

更重要的是,从案例类派生类是不可取的。从案例类派生案例类确实会带来问题(并且编译器会对您大喊大叫)。特别是,编译器不会生成重写的 copy(...) 方法,因此,如果您尝试复制从案例类派生的案例类,您可能会遇到一些奇怪的失败模式。

如果您将案例类保留在任何继承图的叶子中,那就没问题了。

The boilerplate code generated for case classes carries a small but non-zero cost in bytecode. In addition to the copy method, there is hashCode, equals and toString as well as the companion object factory method.

More significant is the fact that it is inadvisable to derive classes from case classes. Deriving a case class from a case class really invites problems (and the compiler will yell at you). In particular, no overriding copy(...) method is generated by the compiler, so you can get some odd failure modes if you try to copy a case class derived from a case class.

If you keep your case classes at the leafs of any inheritance graphs, you'll be fine.

递刀给你 2024-09-23 07:36:50

您将获得定义的任何参数的属性,并且它们将是 val(即,finals)。

case class User(name: String, group: String)
val user = User("jsmith", "admins")

// access both properties
println("name: %s group: %s".format(user.name, user.group))

您也可以通过常规(即非 case 类)获得此行为:

// creates two final public properties as well
class User(val name: String, val group: String)

// creates read/write public properties
class User(var name: String, var group: String)
val user = new User("jsmith", "admins")
user.group = "guests"

Case 类还带来了许多其他东西,例如equal、hashcode 和 toString 的有用实现以及带有工厂方法的伴随对象,消除了使用 new 的需要。

正如您所看到的,案例类不需要实现您想要的目标,但它可以让您快速实现目标。至于副作用,定义案例类会在幕后生成一些代码,以提供上一段中描述的内容。这些通常很有用,我往往不会担心它们,但了解它们还是有好处的。

You will get properites for any parameters defined and they will be vals (i.e., finals)

case class User(name: String, group: String)
val user = User("jsmith", "admins")

// access both properties
println("name: %s group: %s".format(user.name, user.group))

You can get this behavior with regular (i.e., non-case classes) as well:

// creates two final public properties as well
class User(val name: String, val group: String)

// creates read/write public properties
class User(var name: String, var group: String)
val user = new User("jsmith", "admins")
user.group = "guests"

Case classes also bring a lot of other things as well such as a useful implementations of equality, hashcode and toString and a companion object with a factory method that eliminates the need to use new among other things.

As you can see, a case class is not required to achieve what you want but it gets you there quickly. As for side effects, defining a case class generates some bit of code behind the scenes to give you what was described in the previous paragraph. These are often useful and I tend not to worry about them but it is good to know about them.

为你拒绝所有暧昧 2024-09-23 07:36:50

除了已经提到的几点之外,案例类在概念上与 Java 中所谓的“值类”很接近。当然,没有什么可以阻止您编写可变的案例类或具有大量功能但数据很少的案例类,但这可能会让使用您的代码的其他人感到惊讶。根据经验,我想说在创建案例类之前至少要三思而行……

  • 它们需要可变状态,
  • 当您不确定以后是否需要子类(
  • 如果它们的主要目的是计算事物(而不是表示事物))时, ,例如我会考虑使用案例类,那么这些计算就会很
  • 如果您需要对其行为进行细粒度控制(例如,您需要自定义模式匹配),
  • 而当您只需要其中一个“案例类功能”时,性能非常重要
  • 复杂只是为了避免在构造函数参数前面输入“val”作为过度杀伤

Additional to the already mentioned points, a case class is conceptually close to what you would call a "value class" in Java. Of course nothing stops you from writing mutable case classes or case classes with heavy functionality but few data, but this could surprise others working with your code. As a rule of thumb I'd say at least think twice before creating case classes...

  • which need mutable state
  • when you are not sure if you might need subclasses later
  • if their main purpose is to calculate things (not to represent things), and these calculations are complicated
  • if you need fine grained control over their behavior (say, you need custom pattern matching)
  • when performance is really important
  • when you need only one of the "case class feature", e.g. I'd consider using a case class just to avoid typing "val" in front of constructor args as overkill
一世旳自豪 2024-09-23 07:36:50

其他答案都很好,但他们错过的一个真正的风险是案例类具有值相等性,其行为与标准面向对象的身份相等性非常不同。两个 case 对象相等,当且仅当它们的所有字段都相等。这正是某些情况下所需要的,但在另一些情况下却非常出乎意料。特别是,向具有相等值的东西添加可变状态是自找麻烦。您很容易发现自己的对象的散列码随时间而变化,从而导致 HashMap 损坏和其他类似的问题。

为了节省一些击键次数而将某些东西声明为案例类,将您的属性声明为“val”是错误的经济做法,并且有一天会咬您。

The other answers are all fine, but the one real risk they miss is that case classes have value equality, which behaves very differently from standard object-oriented identity equality. Two case objects are equal iff all of their fields are equal. This is exactly what is needed in some cases, but very unexpected in others. In particular, adding mutable state to something with value equality is asking for trouble. You could easily find yourself with objects whose hashcode changes with time, resulting in corrupted HashMaps and other such nastiness.

Declaring something a case class in order to save a few keystrokes declaring your properties as "val" is false economy, and will someday bite you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文