考虑以下用Java编写的类:
class NonNegativeDouble {
private final double value;
public NonNegativeDouble(double value) {
this.value = Math.abs(value);
}
public double getValue() { return value; }
}
它定义了一个名为value
的最终字段,该字段在构造函数中初始化,方法是将其参数称为alike并对其应用函数。
我想在Scala中编写与它类似的东西。起初,我尝试过:
class NonNegativeDouble(value: Double) {
def value = Math.abs(value)
}
但编译器抱怨:错误:重载方法值需要结果类型
显然编译器认为表达式value
中的表达式Math.abs(value)
是指定义的方法。因此,定义的方法是递归的,所以我需要声明它的返回类型。因此,我编写的代码没有按照我的预期执行:我希望value
内的Math.abs(value)
引用构造函数参数value
,而不是指定义的方法。就好像编译器隐式地将this.
添加到Math.abs(this.value)
。
向构造函数参数添加val
或var
(或private ...
变体)似乎没有帮助。
所以,我的问题是:我可以定义一个与构造函数参数同名的属性,但可能是一个不同的值?如果是这样,怎么样?如果没有,为什么?
谢谢!
答案 0 :(得分:17)
解决方案当然是使用另一个名称:
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
像这样使用,initValue
将不是创建的实例的一部分。但是,如果您在def
或模式匹配声明中使用它,那么它将成为该类的每个实例的一部分。
答案 1 :(得分:4)
@Daniel C. Sobral
class NonNegativeDouble(initValue: Double) {
val value = Math.abs(initValue)
}
你的代码是正确的,但“构造函数参数是属性”,这不是真的。
A post from the official site said,
如果是,则将类Foo(x:Int)等参数转换为字段 在一个或多个方法中引用
马丁的回复证实了其真相:
这一切都是正确的,但它应该被视为一种实现 技术。这就是规范对此保持沉默的原因。
通常情况下,我们仍然可以将主构造函数参数视为常规方法参数,但是当任何方法引用参数时,编译器会巧妙地将其转换为私有字段。
如果val前面有任何形式参数,编译器会自动生成一个getter定义。如果var,则另外生成一个setter。见语言准备部分5.3。
这就是主要的构造函数参数。
答案 2 :(得分:2)
您可以考虑参数字段
class NonNegativeDouble(val value: Double, private val name: String ){
if (value < 0) throw new IllegalArgumentException("value cannot be negative")
override def toString =
"NonNegativeDouble(value = %s, name = %s)" format (value, name)
}
val tom = "Tom"
val k = -2.3
val a = new NonNegativeDouble(k.abs, tom)
a: NonNegativeDouble = NonNegativeDouble(value = 2.3, name = Tom)
a.value
res13: Double = 2.3
a.name
<console>:12: error: value name in class NonNegativeDouble cannot be accessed in NonNegativeDouble
a.name
val b = new NonNegativeDouble(k, tom)
java.lang.IllegalArgumentException: value cannot be negative
...
它定义了具有相同名称“value”,“name”的字段和参数。 您可以添加修饰符,例如private ...
答案 3 :(得分:0)
如果是case classes
,则应该是:
case class NonNegativeDouble(private val initValue: Double) {
val value = Math.abs(initValue)
def copy(value: Double = this.value) = NonNegativeDouble(value)
}
需要copy
的实现来防止绑定initValue
参数的编译器的错误版本。
我希望编译器足够聪明,不能保留initValue
的“额外空间”。我还没有验证这种行为。