在Scala中使用类型参数和mixins

Emi*_*l H 3 scala mixins type-parameter roman-numerals

编辑2:

我设法通过使用mixins和类型参数的组合以及下面的代码在RomanNumerals练习中实现我想要的类型安全性.本质上它所做的是在导入所有内容后RomanNumerals我能够写入L X V I,但不是L LX L X导致然后我得到类型不匹配编译器错误(因为那些将是罗马数字的非法组合).现在我想知道这种使用traits,mixins和类型参数的方式是否正常或者我是否滥用语言可以这么说:)是否有更好的方法来实现同类型的安全性更简单/更清洁码?

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]] 
}
Run Code Online (Sandbox Code Playgroud)

编辑:

基于胜利者回答的进一步问题.好的,但如果我在type参数中添加上限和下限以便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
  }
}
Run Code Online (Sandbox Code Playgroud)

或者B在这种情况下仍然可以成为一个班级?如果我知道f参数太适用,那该Foo[B] with B怎么办?有没有办法用它来混合B返回类型?

下面的原始问题

当我在Scala中创建一个对象时,我希望混合一个我得到的特性作为类型参数:

class Foo(val num:Int) { 
  def withM[B](foo:Foo) = new Foo(foo.num) with B
}
Run Code Online (Sandbox Code Playgroud)

这会导致编译错误:

error: class type required but B found
def withM[B](foo:Foo) = new Foo(foo.num) with B
                                              ^
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

class Foo(val num:Int) { 
  def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用:

error: not found: type classOf
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B]
                                              ^
Run Code Online (Sandbox Code Playgroud)

有没有办法解决这个问题?这样withM的返回类型成为Foo with B其中B的类型参数传递给withM

Vik*_*ang 5

这种功能根本不可能(或者不可用)而且,它只能混合特征(和接口),并且只要编译器知道,你的类型参数就可以是Int.

您需要指定具体的特征或接口类型,如下所示:

trait T
class Foo
object Test {
  def apply = new Foo with T
}
Run Code Online (Sandbox Code Playgroud)