我正在使用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
但这绝对不起作用。
有什么想法吗?
答案 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))
^