Scala:约束成员函数的类类型参数

时间:2015-12-16 22:55:27

标签: scala types

如果某个类A的类型参数为T,那么如何针对特定函数进一步约束T?在下面的示例中,我想强制foo只能在TInt(或者您喜欢的子类型)时调用。即new A[Int]().foo()应该编译,但new A[Double]().foo()不应该编译。

我可以通过T => Int中演示的隐式转化foo来实现我想要的效果。然而,这会导致不必要的方法调用 - 隐式发现的证据是身份函数。此外,它看起来不太好......

class A[T] {
  val someValue: T = ???

  def foo()(implicit ev: T => Int): Int = ev(someValue)

  // some ideas that don't quite work
  // def bar[T2 <: Int :EqualTo[T]](t2: T2): T = t2.asInstanceOf[T]
  // def bam[T2 <: T with Int](): Int = someValue.asInstanceOf[Int]

  def thisOneDefinesItsOwnConstraintType[Z <: Int](z: Z): Z = z
  def thisOneDoesNotNeedToConstrainT(t: T): T = someValue
}

如果不需要施放,解决方案会获得奖励积分:)

注意:我知道我可以在类或方法级别定义类型约束(请参阅thisOneDefinesItsOwnConstraintType),但这对我没有帮助,因为我也有一些不需要约束的方法类型(见thisOneDoesNotNeedToConstrainT)。

2 个答案:

答案 0 :(得分:4)

我没有看到一种方法可以做到这一点而没有暗示,因为虽然你可以在类方法上加上一些约束B <: C,但是你要求B <: T很难概括,因为我们不知道C如何与仲裁T相关联。幸运的是,Scala已经为此构建了一个<:<类型类。 <:<[B, T]中生成的Predef实例将提供B <: C

的证据

但请不要相信我的意思,这里是scaladoc所说的:

  

要约束方法参数列表中范围内的任何抽象类型T(不仅仅是方法的自身类型参数),只需添加类型为T&lt;:&lt的隐式参数; U,其中U是必需的上限;或者对于下限,使用:L&lt;:&lt; T,其中L是所需的下限。

例如:

class E
class F extends E
class G extends F

class A[T] {
  def constrained[B <: F](b: B)(implicit ev: B <:< T): B = b
}

在这里,我们为F方法的类型参数B引入contrained的上限。但是,如果 想要保证B <: T(不添加其他类型参数),则可以添加隐式B <:< T

scala> val a = new A[E]
a: A[E] = A@5a63f509

scala> a.constrained(new E)
<console>:15: error: inferred type arguments [E] do not conform to method constrained's type parameter bounds [B <: F]
       a.constrained(new E)
         ^
<console>:15: error: type mismatch;
 found   : E
 required: B
       a.constrained(new E)
                     ^

scala> a.constrained(new F)
res5: F = F@4a668b6e

scala> a.constrained(new G)
res6: G = G@4de4b452

答案 1 :(得分:2)

怎么样:

implicit class AIntOps(a: A[Int]) {
  def test(x: Int) = x
}

使用该方法,测试仅针对A[Int]显示,并且根本不适用于任何其他A