【问题标题】:How to compare Ordered abstract type in Scala trait?如何比较 Scala 特征中的有序抽象类型?
【发布时间】:2012-02-13 15:25:37
【问题描述】:

鉴于下面的代码,foo 方法应该比较operator-wise给定参数barlowerBoundupperBound 都属于相同的抽象类型Bar

trait Foo {
  type Bar <: Ordered[Bar]
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar) = bar >= lowerBound && bar <= upperBound
}

这样可以定义特征Foo。问题从下面的具体类FooImpl开始。

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}

我知道scala.Int 没有实现scala.runtime.RichInt 所做的事情,实际上是scala.math.Ordered[Int]。将类型 Bar 定义为 RichInt 而不是不起作用,因为它不符合 scala.math.Ordered[RichInt]。我第三次尝试将Bar 类型定义为Ordered[Ord],其中Ord 被声明为type Ord,并在FooImpl 中将其定义为Int 也不起作用。

一个可能接近的解决方案是什么样的?

【问题讨论】:

    标签: scala abstract-type


    【解决方案1】:

    可能有更优雅的解决方案,但您可以通过将类型的限制移至方法而不是类型声明来实现:

    trait Foo {
      type Bar
      val lowerBound: Bar
      val upperBound: Bar
      def foo(bar: Bar)(implicit ev: Bar => Ordered[Bar]) = {
        bar >= lowerBound && bar <= upperBound
      }
    }
    

    然后您的FooImpl 就可以正常工作了:

    class FooImpl extends Foo {
      type Bar = Int
      val lowerBound = 0
      val upperBound = 5
    }
    

    来自 REPL:

    scala> new FooImpl()
    res0: FooImpl = FooImpl@2dbbec72
    
    scala> res0.foo(3)
    res1: Boolean = true
    
    scala> res0.foo(7)
    res2: Boolean = false
    

    这里的缺点是可以用无序类型扩展特征(尽管在这种情况下不能调用foo):

    class A // not Ordered
    
    class BrokenFoo extends Foo {
      type Bar = A
      val lowerBound = new A
      val upperBound = new A
    } // compiles
    
    new BrokenFoo().foo(new A) // doesn't compile
    

    或者,您可以将要求保持在类级别(因此阻止任何人创建BrokenFoo),如下所示,但FooImpl 必须稍作更改:

    trait Foo {
      type Bar
      implicit val baz: Bar => Ordered[Bar]
      val lowerBound: Bar
      val upperBound: Bar
      def foo(bar: Bar) = { bar >= lowerBound && bar <= upperBound }
    }
    
    class FooImpl extends Foo {
      type Bar = Int
      val baz = implicitly[Bar => Ordered[Bar]]
      val lowerBound = 0
      val upperBound = 5
    }
    

    这个问题感觉view or context bounds 应该适用,但不幸的是,您似乎不能在type 声明或特征的泛型类型参数中使用它们。

    【讨论】:

    • 是的,如果 OP 愿意把 Foo 变成一个抽象类,'Bar' 类型的成员可以去掉,Foo 的声明的第一行可以做为“抽象类 Foo [条形
    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多