如何创建一个Scala类,该类具有公共getter的private字段,主构造函数采用相同名称的参数

如何创建一个Scala类,该类具有公共getter的private字段,主构造函数采用相同名称的参数,scala,Scala,到目前为止,搜索结果让我相信,如果没有非主构造函数,这是不可能的 class Foo { // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness private var _x = 0 def this(x: Int) { this(); _x = x } def x = _x } val f = new Foo(x = 123) // OK: named p

到目前为止,搜索结果让我相信,如果没有非主构造函数,这是不可能的

class Foo {                      // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness
  private var _x = 0
  def this(x: Int) { this(); _x = x }
  def x = _x
}
val f = new Foo(x = 123)         // OK: named parameter is 'x'
或者牺牲主构造函数中参数的名称(使用命名参数进行调用)

理想情况下,可以这样做:

class Foo(private var x: Int) {  // OK: concise
    // make just the getter public
    public x
}
val f = new Foo(x = 123)         // OK: named parameter is 'x'
我知道命名参数在Java世界中是一个新事物,所以它对大多数人来说可能并不重要,但是来自一种命名参数更流行的语言(Python),这个问题马上就出现了

所以我的问题是:这可能吗?(可能不是),如果不是,为什么(在我看来)如此重要的用例没有被语言设计所发现?我的意思是,代码要么牺牲干净的命名,要么牺牲简洁的定义,这是Scala的标志

<强> P.S.考虑公共字段突然需要私有化,同时保持GETTER公共化的情况,在这种情况下,开发者必须改变1行并添加3行以在保持接口相同的情况下实现效果:

class Foo(var x: Int) {}       // no boilerplate
->


这是否真的是一个设计缺陷是相当有争议的。有人会认为复杂的语法允许这个特殊的用例是不值得的。 此外,Scala毕竟是一种主要的函数式语言,因此在您的程序中不应该经常出现变量,这再次提出了一个问题,即是否需要以特殊的方式处理这个特定用例

但是,似乎您的问题的简单解决方案是在伴随对象中使用
apply
方法:

class Foo private(private var _x: Int) {
  def x = _x
}

object Foo {
  def apply(x: Int): Foo = new Foo(x)
}
用法:

val f = Foo(x = 3)
println(f.x)
val f = new Foo(initialX = 3)
以后编辑

下面是一个与您最初请求的解决方案类似的解决方案,但命名方式有点不同:

class Foo(initialX: Int) {
  private var _x = initialX
  def x = _x
}
用法:

val f = Foo(x = 3)
println(f.x)
val f = new Foo(initialX = 3)

您试图表达的概念,是一个对象,其状态从对象内部是可变的,但从其他对象的角度来看是不变的。。。这可能会被表示为在参与者系统的上下文中的Akka参与者。在actor系统的上下文之外,它似乎是一个Java概念,它将对象的含义移植到Scala

import akka.actor.Actor
class Foo(var x: Int) extends Actor {
  import Foo._
  def receive = {
    case WhatIsX => sender ! x
  } 
}
object Foo {
  object WhatIsX
}

我很感激你的回答,但是。。。关于“这个特殊的用例”,我谦虚地说,这不是一个特殊的用例,而是一个非常常见的用例,如果我错了,请纠正我。。。至于伴生对象方法,它在从公共到私有的过程中改变了接口(更不用说它是另外两行样板文件了)。我在我检查过的库中很少看到这种模式。诚然,这是基于我自己的经验。我已经更新了我的答案,找到了一个样本更少的解决方案。因为在Scala中,变量和方法在一个类中共享相同的名称空间,所以我认为它不会比this@ErikAllik,不,这在惯用Scala代码中根本不是常见的用例,主要是因为它与可变性有关。惯用的Scala代码将可变状态的使用限制到了绝对最小。顺便说一句,当您的代码将
var
作为其接口的一部分,然后将其更改为
def
时,您就有可能破坏代码的客户端,因此是否应该进行这种重构是很有争议的。@Vladimitaveveveve:同意-我在不久前已经相应地更新了我的问题:)