РЕДАКТИРОВАТЬ 2:
Мне удалось добиться безопасности типов, которую я хотел в своем упражнении с RomanNumerals, используя комбинацию mixins и параметров типов с кодом ниже. По сути, после импорта всего в RomanNumerals
я могу написать L X V I
, но не L L
или X L X
, потому что тогда я получаю ошибку компиляции несоответствия типов (поскольку это были бы недопустимые комбинации римских цифр ). Теперь мне интересно, если этот способ использования свойств, миксинов и параметров типов считается нормальным или я злоупотребляю языком, если можно так выразиться :) Есть ли лучший способ достижения такого же типа безопасности типов с помощью более простого / чистого код
object RomanNumerals {
trait Numeral {
def num:Int
}
trait NumeralI[N<:Numeral] extends Numeral
trait NumeralV[N<:Numeral] extends NumeralI[N] {
def I = new RomanNumeral[Numeral](1 + this.num) with Numeral
def II = new RomanNumeral[Numeral](2 + this.num) with Numeral
def III = new RomanNumeral[Numeral](3 + this.num) with Numeral
}
trait NumeralX[N<:Numeral] extends NumeralV[N] {
def IV = new RomanNumeral[Numeral](4
+ this.num) with Numeral
def V = new RomanNumeral[NumeralI[Numeral]](5
+ this.num) with NumeralV[NumeralI[Numeral]]
def IX = new RomanNumeral[Numeral](9
+ this.num) with Numeral
}
trait NumeralL[N<:Numeral] extends NumeralX[N] {
def X = new RomanNumeral[NumeralV[Numeral]](10
+ this.num) with NumeralX[NumeralV[Numeral]]
def XX = new RomanNumeral[NumeralV[Numeral]](20
+ this.num) with NumeralX[NumeralV[Numeral]]
def XXX = new RomanNumeral[NumeralV[Numeral]](30
+ this.num) with NumeralX[NumeralV[Numeral]]
}
class RomanNumeral[T <: Numeral](val num:Int) {
override def toString = num toString
def apply[N >: T <: Numeral](rn:NumeralI[N]) =
new RomanNumeral[Numeral](rn.num + num) with Numeral
def apply[N >: T <: Numeral](rn:NumeralV[N]) =
new RomanNumeral[NumeralI[Numeral]](rn.num
+ num) with NumeralV[NumeralI[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralX[N]) =
new RomanNumeral[NumeralV[Numeral]](rn.num
+ num) with NumeralX[NumeralV[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralL[N]) =
new RomanNumeral[NumeralX[Numeral]](rn.num
+ num) with NumeralL[NumeralX[Numeral]]
}
val I = new RomanNumeral[NumeralI[Numeral]](1) with NumeralI[Numeral]
val II = new RomanNumeral[NumeralI[Numeral]](2) with NumeralI[Numeral]
val III = new RomanNumeral[NumeralI[Numeral]](3) with NumeralI[Numeral]
val IV = new RomanNumeral[NumeralI[Numeral]](4) with NumeralI[Numeral]
val V = new RomanNumeral[NumeralI[Numeral]](5) with NumeralV[NumeralV[Numeral]]
val IX = new RomanNumeral[NumeralI[Numeral]](9) with NumeralI[Numeral]
val X = new RomanNumeral[NumeralV[Numeral]](10) with NumeralX[NumeralX[Numeral]]
val XX = new RomanNumeral[NumeralV[Numeral]](20) with NumeralX[NumeralX[Numeral]]
val XXX = new RomanNumeral[NumeralV[Numeral]](30) with NumeralX[NumeralX[Numeral]]
val XL = new RomanNumeral[NumeralV[Numeral]](40) with NumeralX[NumeralX[Numeral]]
val L = new RomanNumeral[NumeralX[Numeral]](50) with NumeralL[NumeralL[Numeral]]
}
EDIT:
Дальнейший вопрос основан на ответе Виктора. Хорошо, но что, если я добавлю верхние и нижние границы к параметру типа, чтобы B был признаком? Э.Г.
trait Bar
class Foo[T<:Bar](n:Int) {
def apply[B >: T <: Bar](f:Foo[B]) = {
new Foo[B](n + f.n) with B
}
}
Или, может быть, B
все еще может быть классом в этом случае? Что если я знаю, что аргумент f тоже относится к типу Foo[B] with B
? Есть ли способ использовать это для смешивания B
с типом возврата?
ОРИГИНАЛЬНЫЙ ВОПРОС НИЖЕ
Я хочу смешать черту, которую я получаю в качестве параметра типа при создании объекта в Scala:
class Foo(val num:Int) {
def withM[B](foo:Foo) = new Foo(foo.num) with B
}
Это приводит к ошибке компиляции:
error: class type required but B found
def withM[B](foo:Foo) = new Foo(foo.num) with B
^
Я также пробовал:
class Foo(val num:Int) {
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
}
Но это не работает:
error: not found: type classOf
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
^
Есть ли способ обойти это? Таким образом, возвращаемый тип withM становится Foo with B
, где B
- параметр типа, передаваемый в withM