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



给定一个具有类型参数T的类A,如何进一步约束特定函数的T?在下面的示例中,我想强制要求只有当TInt(或者的子类型,如果您愿意的话)时才能调用foo。即new A[Int]().foo()应该编译,但new A[Double]().foo()不应该编译。

foo所示,我可以通过隐式转换T => Int来实现我想要的。然而,这会导致不必要的方法调用——隐式找到的证据是身份函数。而且,它看起来不好看。。。

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)。

如果没有隐式,我看不出有什么方法可以做到这一点,因为虽然你可以在类方法上设置一些约束B <: C,但你对B <: T的要求很难推广,因为我们不知道C如何与任意的T相关联。幸运的是,Scala已经为此构建了<:<类型的类。在CCD_ 19中生成的CCD_ 18的实例将提供CCD_。

但不要只相信我的话,以下是scaladoc要说的:

要约束方法参数列表中作用域中的任何抽象类型T(而不仅仅是方法自己的类型参数),只需添加类型为T<的隐式参数:<U、 其中U是所需的上界;或者对于下限,使用:L<:<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
}

这里,我们引入了contrained方法的类型参数BF的上界。但是,如果希望保证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

怎么样:

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

使用该方法,测试将只出现在A[Int]上,而不适用于任何其他A

最新更新