scala - 在 Scala 中使用类型参数和混合

标签 scala mixins roman-numerals type-parameter

编辑 2:

在使用 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]] 
}

编辑:

基于胜利者回答的进一步问题。好的,但是如果我为类型参数添加上限和下限以使 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 参数 too apply 的类型是 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

的类型参数

最佳答案

这种功能根本不可能(或不可用) 此外,只能混合特征(和接口(interface)),并且你的类型参数可以是编译器所知的 Int。

您需要指定一个具体的特征或接口(interface)类型:

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

关于scala - 在 Scala 中使用类型参数和混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3307404/

相关文章:

scala - 如何使用 Slick 的 insertOrUpdate 返回整行

scala - 将 Free Monad 与 Either 一起使用

css - Less 中基于颜色的条件逻辑

java - 在 Java 中重复提示直到字符串中的所有字符都可以接受

java - 整数的罗马表示

javascript - 用 RegEx 替换罗马数字 I-XXX

java - Lucene 空间 : Sorting by Distance

scala infinite rx observable creation - 如何正确地做到这一点?

sass - 如何在SASS中将mixin作为另一个mixin的参数传递

css - SCSS 问题,适用于 fiddle ,但不适用于本地