如何使用公共 getter 创建一个带有私有字段的 Scala 类,以及采用同名参数的主构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18728968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:39:26  来源:igfitidea点击:

How to create a Scala class with private field with public getter, and primary constructor taking a parameter of the same name

scala

提问by Erik Kaplun

Search results so far have led me to believe this is impossible without either a non-primary constructor

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

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'

or sacrificing the name of the parameter in the primary constructor (making calls using named parameters ugly)

或者在主构造函数中牺牲参数的名称(使用命名参数进行调用很难看)

class Foo(private var _x: Int) { // OK: concise
   def x = _x
}
val f = new Foo(_x = 123)        // NOT OK: named parameter should be 'x' not '_x'

ideally, one could do something like this:

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

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'

I know named parameters are a new thing in the Java world, so it's probably not that important to most, but coming from a language where named parameters are more popular (Python), this issue immediately pops up.

我知道命名参数在 Java 世界中是一个新事物,所以它对大多数人来说可能不是那么重要,但是来自命名参数更流行的语言(Python),这个问题立即弹出。

So my question is: is this possible? (probably not), and if not, why is such an (in my opinion) important use case left uncovered by the language design? By that, I mean that the code either has to sacrifice clean naming or concise definitions, which is a hallmark of Scala.

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

P.S.Consider the case where a public field needs suddenly to be made private, while keeping the getter public, in which case the developer has to change 1 line and add 3 lines to achieve the effect while keeping the interface identical:

PS考虑一下一个公共字段突然需要私有的情况,同时保持 getter 公共,在这种情况下,开发者必须更改 1 行并添加 3 行才能在保持界面相同的情况下实现效果:

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

->

->

class Foo {                    // lots of boilerplate
  private var _x: Int = 0
  def this(x: Int) { this(); _x = x }
  def x = _x
}

采纳答案by Marius Danila

Whether this is indeed a design flaw is rather debatable. One would consider that complicating the syntax to allow this particular use case is not worthwhile.

这是否确实是一个设计缺陷是值得商榷的。人们会认为将语法复杂化以允许这种特定用例是不值得的。

Also, Scala is after all a predominantly functional language, so the presence of vars in your program should not be that frequent, again raising the question if this particular use case needs to be handled in a special way.

此外,Scala 毕竟是一种主要的函数式语言,因此程序中变量的出现不应该那么频繁,这再次引发了这个特定用例是否需要以特殊方式处理的问题。

However, it seems that a simple solution to your problem would be to use an applymethod in the companion object:

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

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

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

Usage:

用法:

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

LATER EDIT:

稍后编辑

Here is a solution similar to what you originally requested, but that changes the naming a bit:

这是一个类似于您最初要求的解决方案,但稍微改变了命名:

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

Usage:

用法:

val f = new Foo(initialX = 3)

回答by Alex

The concept you are trying to express, which is an object whose state is mutable from within the object and yet immutable from the perspective of other objects ... that would probably be expressed as an Akka actor within the context of an actor system. Outside the context of an actor system, it would seem to be a Java conception of what it means to be an object, transplanted to Scala.

您试图表达的概念是一个对象,它的状态在对象内部是可变的,但从其他对象的角度来看是不可变的……这可能会在演员系统的上下文中表示为 Akka 演员。在演员系统的上下文之外,它似乎是一个 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
}