scala - Scala 中的内部类与不变性

标签 scala immutability inner-classes

请看以下玩具示例:

case class Person(name: String, address: Person#Address = null) {
  case class Address(street: String, city: String, state: String) {
    def prettyFormat = s"To $name of $city" // note I use name here
  }

  def setAddress(street: String, city: String, state: String): Person =
    copy(address=Address(street,city,state))

  def setName(n: String): Person = copy(name=n)
}

你看到那里有错误吗?是的,以下代码将在两种情况下打印相同的消息 (John):
val p1 = Person("John").setAddress("Main", "Johntown", "NY")
println(p1.address.prettyFormat) // prints To John of Johntown
val p2 = p1.setName("Jane")
println(p2.address.prettyFormat) // prints To John of Johntown

这自然是因为在 set 方法中保留了 Address 中的 $outer 引用,所以 p2 内部对象仍然引用 John。该问题可以通过以下方式或通过重新创建 Address 对象来解决(如果我们在案例类中预先制作了复制构造函数,那不是很好吗?):
def setName(n: String) = copy(name=n).setAddress(address.street,address.city,address.state)

然而,如果有几个像这样的内部对象和数十个像 setName 这样的方法,问题就会变得更加烦人。所以我的结论是不变性和类内部类相互不兼容 .

问题:对于嵌套不可变对象(immutable对象)的结构,是否存在设计模式或有用的习惯用法,其中内部对象需要访问外部对象才能完成工作。

到目前为止,我已经考虑将 person 隐式传递给 prettyFormat 或将内部方法包装到 Reader monad 中,因此当前 person 将应用于 prettyFormat 返回的 monad。还有什么好主意吗?

最佳答案

这并不是说不变性和类内部类相互不兼容,而是当您创建内部地址类时,它会绑定(bind)到该 Person 实例(否则您将使用静态内部类,即在伴随对象中定义 Address )。

您的问题更多在于 copy 的语义。为不考虑内部类的案例类提供的方法。因此,要么放弃不变性,要么在修改时创建一个真正的新人:

def setName(n: String): Person = Person(n, street, city, state)

请注意,我不应该直接通过 Address实例到 Person() ,你的定义是每个地址类型是一个人的一部分,只对那个人有意义,所以它不能存在于那个人之外,我不能将它从外部传递给正在创建的新人.同样,如果不是这种情况,那么您需要重新考虑使用不同语义的结构。

就个人而言,我认为以下内容作为对域的描述更加清晰/直观:
case class Address(street: String, city: String, state: String)
case class Person(name: String, address: Address) {
   def prettyFormat = s"To $name of ${address.city}"
} 

然后您可以创建地址/人员的副本,而无需担心和完全不变。

关于scala - Scala 中的内部类与不变性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32305016/

相关文章:

Java/Scala 大整数粘贴

java - 如何防止不可变对象(immutable对象)中的可变对象发生更改

Java:内部类访问彼此的私有(private)变量 - 封装外部 API 的良好实践?

安卓 :get an object from an inner class

scala - 解析 F 有界多态性中的类型

scala - Akka 长时间运行的初始化和 Future 回调中的崩溃 actor

immutability - 我如何强制结构的字段在 Rust 中始终不可变?

java - Mockito 有没有办法从内部类运行监视对象的 stub 方法?

scala - 流畅的查询优化

python - 在 Python 中创建不可变对象(immutable对象)