Scala Properties Вопрос - PullRequest
       37

Scala Properties Вопрос

11 голосов
/ 11 ноября 2010

Я все еще изучаю Scala, но мне показалось интересным то, что Scala стирает грань между методами и полями. Например, я могу создать такой класс ...

class MutableNumber(var value: Int)

Ключевым моментом здесь является то, что переменная в аргументе-конструкторе автоматически позволяет мне использовать поле 'value' как getter / setter в java.

// 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. Если я использую named-параметры, мой 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?

Спасибо!

Ответы [ 3 ]

11 голосов
/ 11 ноября 2010

Вы можете использовать тот же прием, что и классы дел: используйте объект-компаньон.

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
2 голосов
/ 13 ноября 2010
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}
2 голосов
/ 12 ноября 2010

Спасибо за ответ! Кроме того, я думаю, что ребята из Scala могут знать, что есть проблема:

Что нового в Scala 2.8: Именованные параметры и параметры по умолчанию

... До сих пор имена аргументов были несколько произвольным выбором для разработчиков библиотек и не считались важной частью API. Это внезапно изменилось, так что вызов метода mkString (sep = "") не будет скомпилирован, если в более поздней версии аргумент sep был переименован в separator.

Scala 2.9 реализует изящное решение этой проблемы, но пока мы этого ждем, будьте осторожны при обращении к аргументам по имени, если их имена могут измениться в будущем.

...