Scala性质问题

Scala性质问题,scala,properties,scala-2.8,javabeans,named-parameters,Scala,Properties,Scala 2.8,Javabeans,Named Parameters,我还在学习Scala,但有一件事我觉得很有趣,Scala模糊了方法和字段之间的界限。例如,我可以构建这样的类 class MutableNumber(var value: Int) 这里的关键是构造函数参数中的var自动允许我像java中的getter/setter一样使用“value”字段 // use number... val num = new MutableNumber(5) num.value = 6 println(num.value) 如果要添加约束,可以切换到使用方法来代替

我还在学习Scala,但有一件事我觉得很有趣,Scala模糊了方法和字段之间的界限。例如,我可以构建这样的类

class MutableNumber(var value: Int)
这里的关键是构造函数参数中的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的情况下添加约束


谢谢

您可以使用与case类相同的技巧:使用伴随对象

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>新示例。可变编号(5)
:10:错误:无法在对象$iw中访问构造函数MutableNumber
新示例。可变数字(5)
^
scala>Example.MutableNumber(值=2)
res0:Example.MutableNumber=mutable2
scala>Example.MutableNumber()
res1:Example.MutableNumber=mutable0

谢谢你的回答!另一方面,我认为Scala的人可能意识到了一个问题:

Scala 2.8的新增功能:命名和默认参数

。。。 到目前为止,参数的名称对于库开发人员来说是一个有点随意的选择,并不被认为是API的重要组成部分。这一点突然发生了变化,因此,如果参数sep在更高版本中重命名为separator,那么对mkString(sep=”“)的方法调用将无法编译

Scala2.9为这个问题实现了一个简洁的解决方案,但是在我们等待这个解决方案的同时,如果参数的名称将来可能会发生变化,请谨慎地按名称引用参数

可以修改大括号内任何类的所有成员

val n = new MutableNumber{value = 17}

有趣!因此,通过隐藏构造函数,我强制每个人使用伴随对象。如果我想让MutableInteger本身成为一个case类呢?我知道,如果我只是将“case”放在类定义之前,Scala会自动为我创建伴生对象……这个解决方案仍然有效吗?是的,如果您为一个case类显式定义了伴生对象,那么该对象的成员将合并到生成的对象中(并且可以重写,例如,如果您想提供一个经过调整的
Companion.apply()
方法,但保留自动生成的
unapply
)。@shj-No,这不起作用,因为case类假定直接(不受保护)访问构造函数变量。您这样做是因为需要保护(以
的形式)(_value>=0)在本例中为
)。scala模式匹配是否需要直接访问构造函数?我认为scala添加伴生对象的原因之一是,您不需要显式使用构造函数。我是否应该在case类中使用guards?@David-如何覆盖自动生成的apply()方法?当我尝试这样做时,我得到了“error:method apply定义了两次”。这确实有一个缺点,就是为每个使用大括号的可变数字实例化创建一个匿名。Scala 2.9中的整洁解决方案是什么?
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}