11

私はまだ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)

制約を追加したい場合は、instance-fieldsの代わりにメソッドを使用するように切り替えることで追加できます。

// 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)

これに対するエレガントな解決策はありますか?APIを壊さずに後で制約を追加できるように、MutableNumberクラスをどのように設計する必要がありますか?

ありがとう!

4

3 に答える 3

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
于 2010-11-11T20:38:14.313 に答える
2

答えてくれてありがとう!余談ですが、Scala-guysは問題があることに気付いているかもしれません。

Scala 2.8の新機能:名前付きパラメーターとデフォルトパラメーター

...これまで、引数の名前はライブラリ開発者にとってやや恣意的な選択であり、APIの重要な部分とは見なされていませんでした。これは突然変更されたため、後のバージョンで引数sepの名前がseparatorに変更された場合、mkString(sep = "")のメソッド呼び出しはコンパイルに失敗します。

Scala 2.9はこの問題に対するきちんとした解決策を実装していますが、それを待っている間、引数の名前が将来変更される可能性がある場合は、名前で引数を参照することに注意してください。

于 2010-11-11T22:50:39.927 に答える
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}
于 2010-11-12T23:01:04.847 に答える