在Scala中使用类型参数和混入(mixins)

3

编辑2:

通过使用混合和类型参数的组合,我成功地在我的罗马数字练习中实现了所需的类型安全。本质上,它的作用是在导入RomanNumerals中的所有内容后,我可以写出L X V I,但不能写出L LX 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]] 
}

编辑:

根据Victor的回答,进一步提出问题。如果我将上限和下限添加到类型参数中,使B成为一个trait,会怎样呢?例如:

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对象时混入作为类型参数得到的trait:

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 的类型参数。

1个回答

5

这种功能是不可能实现的(或者说不可用)。

此外,只能混入特质(和接口),对于编译器来说,您的类型参数可以是Int。

您需要指定一个具体的特质或接口类型:

trait T
class Foo
object Test {
  def apply = new Foo with T
}

编辑了问题,添加了一些信息/新问题 :) - Emil L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接