给定一个具有类型参数T
的类A
,如何进一步约束特定函数的T
?在下面的示例中,我想强制要求只有当T
是Int
(或者的子类型,如果您愿意的话)时才能调用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
方法的类型参数B
的F
的上界。但是,如果也希望保证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