Int和Char scala插值(泛型和上界)

时间:2016-11-08 15:00:58

标签: scala generics

我正在使用scala中的泛型和上限,我遇到了以下问题:

让我们说我有以下功能(我只期望Int或Char):

def foo[T](tuple: Tuple2[T, T]) = tuple match {
  case Tuple2(x: Int, y: Int) => (x to y).toArray
  case Tuple2(x: Char, y: Char) => (x to y).toArray
}

我希望有一个更好的压缩形式,如:

def foo2[T >: Int with Char <: AnyVal](tuple: (T, T))  = (tuple._1 to tuple._2).toArray

但这绝对不起作用。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

在这里,您可以使用相对可怕的签名来获得实施的(tup._1 to tup._2).toArray语法:

def foo[T 
  <% RangedProxy[T]{ type ResultWithoutStep <: TraversableOnce[T] } 
  : ClassTag
](tup: (T, T))

打破它:
T可隐式转换为RangedProxy[T],这是定义to方法的地方。结果类型to取决于类型成员 ResultWithoutStep,我们必须确保它是TraversableOnce[T]的子类,以便我们可以调用.toArray在它上面。

请注意,上述签名或@ MichaelZajac的答案都不会处理您所要求的&#34;只能使用Int和Char&#34;。实际上,满足这一要求的最佳方法是使用类型类

sealed trait Fooable[T] extends ((T, T) => Array[T])
object Fooable {
  private def impl[T](f: (T, T) => Array[T]) = 
    new Fooable[T]{ def apply(min: T, max: T): Array[T] = f(min, max) }
  implicit val intFooable = impl[Int]{ (i,j) => (i to j).toArray }
  implicit val charFooable = impl[Char]{ (a,b) => (a to b).toArray }
}
def foo[T: Fooable](tup: (T, T)) = implicitly[Fooable[T]].apply(tup._1, tup._2)

不幸的是,对于这个特定问题,类型类方法有点麻烦,但是如果你专注于implicit val xFooable,你会发现它类似于以下内容:

// unfortunately this doesn't work due to type erasure on the JVM,
// which is why we've resorted to typeclasses as above
def foo(tup: (Int, Int)) = ...
def foo(tup: (Char, Char)) = ...

答案 1 :(得分:1)

简单地自己调用NumericRange.inclusive会更容易,而不是尝试整理使用to语法所需的含义和类型约束。如果我们需要隐式Integral,我们将知道如何构造一个步长为1的范围(由Integral实例提供)。我们还需要ClassTag[A]来一般性地创建Array

import scala.reflect.ClassTag
import scala.collection.immutable.NumericRange

def foo2[A >: Int with Char : ClassTag](tuple: (A, A))(implicit int: Integral[A]) = 
   NumericRange.inclusive(tuple._1, tuple._2, int.one).toArray

scala> foo2(('a', 'z'))
res13: Array[Char] = Array(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)

scala> foo2((1, 10))
res14: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

其他人失败(如果你希望他们使用类型约束):

scala> foo2((1L, 10L))
<console>:19: error: could not find implicit value for parameter int: Integral[AnyVal]
       foo2((1L, 10L))
           ^