我还在学习Scala,但我认为有趣的一点是Scala模糊了方法和字段之间的界限。例如,我可以建立一个这样的类......
class MutableNumber(var value: Int)
这里的关键是constructor-argument中的var自动允许我像java中的getter / setter一样使用'value'字段。
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
如果我想添加约束,我可以通过使用方法代替实例字段来实现:
// require all mutable numbers to be >= 0
class MutableNumber(private var _value: Int) {
require(_value >= 0)
def value: Int = _value
def value_=(other: Int) {
require(other >=0)
_value = other
}
}
由于API不会更改,客户端代码不会中断:
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
我的挂机是添加到Scala-2.8的命名参数功能。如果我使用命名参数,我的API 会更改, 会破坏api。
val num = new MutableNumber(value=5) // old API
val num = new MutableNumber(_value=5) // new API
num.value = 6
println(num.value)
这有什么优雅的解决方案吗?我应该如何设计我的MutableNumber类,以便以后可以在不破坏API的情况下添加约束?
谢谢!
答案 0 :(得分:11)
您可以使用与案例类相同的技巧:使用配套对象。
object Example {
class MutableNumber private (private var _value: Int) {
require (_value >= 0)
def value: Int = _value
def value_=(i: Int) { require (i>=0); _value = i }
override def toString = "mutable " + _value
}
object MutableNumber {
def apply(value: Int = 0) = new MutableNumber(value)
}
}
这里它正在工作(并证明,构建时,你必须使用该对象进行创建,因为构造函数被标记为私有):
scala> new Example.MutableNumber(5)
<console>:10: error: constructor MutableNumber cannot be accessed in object $iw
new Example.MutableNumber(5)
^
scala> Example.MutableNumber(value = 2)
res0: Example.MutableNumber = mutable 2
scala> Example.MutableNumber()
res1: Example.MutableNumber = mutable 0
答案 1 :(得分:2)
谢谢你的回答!顺便说一句,我认为Scala人可能会意识到存在问题:
Scala 2.8中的新功能:命名和默认参数
... 到目前为止,参数的名称对于库开发人员来说有点武断,并且不被认为是API的重要部分。这突然发生了变化,因此如果在更高版本中将参数sep重命名为分隔符,则对mkString(sep =“”)的方法调用将无法编译。
Scala 2.9为这个问题实现了一个简洁的解决方案,但是在我们等待的时候,如果他们的名字将来可能发生变化,请谨慎引用名称参数。
答案 2 :(得分:2)
class MutableNumber {
private var _value = 0 //needs to be initialized
def value: Int = _value
def value_=(other: Int) {
require(other >=0) //this requirement was two times there
_value = other
}
}
你可以修改花括号中的任何类的所有成员
val n = new MutableNumber{value = 17}