5.17. Klasy wartości
Klasy rozszerzające AnyVal są zwane klasami wartości. Przykładem takiej klasy jest ValueClass1.
Plik ValueClass1.scala: class ValueClass1(val value: Int) extends AnyVal
Instancje takich klas nie są reprezentowane na maszynie wirtualnej jako osobne obiekty. Przykładowo, kompilator w przypadku obu metod (add1 i add2) z klasy Add generuje kod bajtowy działający na prymitywnych wartościach całkowitych, mimo że na poziomie języka ta pierwsza obsługuje wartości typu Int, a ta druga wartości typu ValueClass1.
Plik Add.scala: class Add { def inc1(x: Int) = x+1 def inc2(x: ValueClass1) = new ValueClass1(x.value+1) }
Klasy wartości podlegają różnym ograniczeniom. Muszą mieć dokładnie jeden parametr będący wartością zadeklarowaną z przedostkiem val, nie mogą definiować żadnych pól składowych, ani dodatkowych konstruktorów.
scala> class ValueClass2(value:Int) extends AnyVal <console>:10: error: value class parameter must be a val and not be private[this] class ValueClass2(value:Int) extends AnyVal ^ scala> class ValueClass3(val value:Int) extends AnyVal { val value2:Double=1 } <console>:10: error: field definition is not allowed in value class class ValueClass3(val value:Int) extends AnyVal { val value2:Double=1 } ^ scala> class ValueClass4(val value:Int) extends AnyVal { def this()=this(0) } <console>:10: error: secondary constructor is not allowed in value class class ValueClass4(val value:Int) extends AnyVal { def this()=this(0) } ^
W pliku Decimal.scala zdefiniowana jest klasa wartości Decimal reprezentująca liczby mające dwie cyfry po przecinku.
Plik Decimal.scala: class Decimal(val value:Int) extends AnyVal { def +(x:Decimal) = new Decimal(value+x.value) def -(x:Decimal) = new Decimal(value-x.value) def *(x:Decimal) = new Decimal(value*x.value/100) def toInt = value/100 def toDouble = value.toDouble/100 override def toString = f"${value/100}.${value.abs%100}%02d" }
Wartość value jest liczbą całkowitą typu Int, sto razy większą od wartości reprezentowanej przez instancję klasy. Również tworząc instancje tej klasy należy jako argument konstruktora podać wartość całkowitą sto razy większą.
scala> val a = new Decimal(515) a: Decimal = 5.15 scala> val b = new Decimal(-314) b: Decimal = -3.14
Poniższe wyrażenia prezentują przykłady wykorzystania wartości typu Decimal.
scala> a+b res0: Decimal = 2.01 scala> a-b res1: Decimal = 8.29 scala> a*b res2: Decimal = -16.17
scala> a.toInt res3: Int = 5 scala> a.toDouble res4: Double = 5.15
Specyfikacja języka Scala opisuje klasy wartości w punkcie 12.2. |