【问题标题】:Difference Scala Class Declaration差异 Scala 类声明
【发布时间】:2019-01-25 07:54:18
【问题描述】:

我想问一下下面这两个类声明有什么区别。

class Person(name: String, age: Int)

class Person() {
  var name: String = ""
  var age: Int = 0
}

【问题讨论】:

    标签: scala class declaration


    【解决方案1】:
    class Person(name: String, age: Int)
    

    nameage 是构造函数参数。因此它们是:

    • 必需 - 为了创建Person 实例
    • 不可变 - 值无法更改
    • private -(默认),不能通过类实例访问

    class Person() {
      var name: String = ""
      var age: Int = 0
    }
    

    nameage 是类数据成员。它们是:

    • 在构造期间未指定 - 但为每个 Person 实例赋予相同的默认值
    • 可变 - 因为它们是var 变量
    • public -(默认)并且可以通过类实例访问和修改

    那么,有什么区别呢?几乎所有东西。

    【讨论】:

    • 感谢您的回答! :)
    • @Lockna 如果其中一个答案解决了您的问题,那么请稍等一下accept an answer and mark the question as solved
    • 起来,对不起。 ?
    • 请注意 Person(name: String, age: Int) 不会将 nameage 添加为类成员(甚至不是私有成员),除非它们在方法中使用(因为编译器必须存储该值某处)。如果只在构造时使用它们来声明其他变量,则参数将永远不会成为类成员。在这些情况下,它们仍然是方法(构造函数)的简单参数,因此谈论它们是公共/私有(或可变/不可变,但如果您尝试改变参数,即使编译器也会提到 vals)可能会令人困惑。
    • @francoisr 虽然在这种特殊情况下在技术上是正确的,但将nameage 描述为“不可变”和“私有”可能在@987654336 的每个非病理情况下更有用@ 和 age 实际上在 Person 的某个地方使用。如果使用它们(可能是大多数时候),它们确实是作为privatefinal 字段实现的。试试class Person(name: String, age: Int) { override def toString = name + age }; classOf[Person].getDeclaredFields
    【解决方案2】:

    第一个声明使用nameage作为构造函数参数,但是它们并没有成为类的成员,也就是说你不能写person.name

    对于初学者来说,第二行可以认为是写class Person(var name: String = " ", var age: Int = 0)的更复杂的方式。它实际上并没有转化为完全相同的东西:您的版本创建一个具有单个构造函数参数和两个公共变量的类,而我的版本具有一个具有 2 个具有默认值的参数的构造函数。除非您有充分的理由以自己的方式声明它,否则通常最好这样写:

    val person = new Person("Andrew", 11)
    

    val person = new Person()
    person.name = "Andrew"
    person.age = 11 
    

    这是您的第二个版本会强制您执行的操作。

    请注意,在 Scala 中,您将主要使用值(常量)而不是变量,因此您实际上通常会使用 class Person(val name: String = " ", val age: Int = 0)。对于像这样的简单数据类型,人们通常使用case class

    case class Person(name: String, age: Int)
    

    在这种情况下,两个参数都被认为是公开的和不可变的。修改人名的唯一方法是使用新名称创建另一个 Person 实例:

    val andrew = Person("Andrew", 11)
    val will = andrew.copy(name="Will") # Will is also 11
    

    案例类将自动为您提供正确的equalshashCode 实现,以及我上面使用的copy 方法。您可以在互联网上轻松找到有关它们的更多信息。

    【讨论】:

    • 第二个版本和你写的完全不一样。 class P2(var name: String = " ", var age: Int = 0) 创建了一个类 P2,它带有一个相当复杂的构造函数和两个默认参数,而原来的 class P1() { var name: String = " "; var age: Int = 0 } 创建了一个具有更简单的 nullary 构造函数的类。
    • 感谢您的回答! :)
    • @AndreyTyukin 你是对的,但从这个问题我也假设作者是 Scala 的新手,所以我不想太明确。我将编辑答案以澄清。
    • @francoisr 您不必“过于明确”,因为您首先不必说任何有关默认参数或案例类的内容。这个问题没有询问任何关于默认参数或案例类的内容,所以说实话,我不确定几乎整个帖子(除了第一句话)与这个问题有什么关系?
    • 恕我直言,这个问题可能是由 Scala 新手提出的,所以我不只是回答问题本身,而是建议其他更惯用的方式来表达我认为作者正在尝试做的事情。你还是不同意我的回答是正确的吗?
    猜你喜欢
    • 1970-01-01
    • 2013-12-06
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2017-11-26
    • 2013-05-23
    相关资源
    最近更新 更多