在TraversableOnce
中,有一个sum
方法只有在包含的类型为Numeric
时才可用(否则它将无法编译)。我想知道这是否可用于其他情况(以避免运行时检查)。
特别是我们有两个特征A和B的情况。我们希望有一个方法f
只有在对象继承 A和B时才能使用。但不是如果它只延伸其中一个。我不想再制作另一个trait AB extends A with B
。我只是希望无法使用f
,如果不是两个特征都被继承。
package com.example
trait Base
trait Foo extends Base {
def g = println("foo bar " + toString)
}
trait Bar extends Base {
/* If this is both Foo and Bar, I can do more */
def f = {
if (!this.isInstanceOf[Foo]) error("this is not an instance of Foo")
this.asInstanceOf[Foo].g
}
}
object Test {
def main(args: Array[String]): Unit = {
object ab extends Foo with Bar
object ba extends Bar with Foo
object b extends Bar
ab.f
ba.f
// I don't want next line to compile:
try { b.f } catch { case e: RuntimeException => println(e) }
}
}
编辑:解决方案,感谢@Aaron Novstrup
trait Bar extends Base { self =>
def f(implicit ev: self.type <:< Foo) = {
//self.asInstanceOf[Foo].g // [1]
ev(this).g // [2]
}
}
现在在main
中,b.f
无法编译。尼斯
编辑2:改变行[1]至[2]反映@Aaron Novstrup的答案变化
编辑3:不使用self
反映@Aaron Novstrup回答的变化
trait Bar extends Base {
/* If this is both Foo and Bar, I can do more */
def f(implicit ev: this.type <:< Foo) = {
ev(this).g
}
}
答案 0 :(得分:8)
是的,你可以:
trait A {
def bar = println("I'm an A!")
}
trait B {
def foo(implicit ev: this.type <:< A) = {
ev(this).bar
println("and a B!")
}
}
如果对象的静态类型(在呼叫站点)扩展evidence
,编译器将只能提供A
参数。
答案 1 :(得分:3)
知道总和的签名是
def sum [B >: A] (implicit num: Numeric[B]) : B
您似乎假设数字类型扩展Numeric,但事实并非如此。实际上它们被隐式转换为 Numeric ,在 Int 的情况下,隐式使用的是 scala.math.Numeric.IntIsIntegral ,它们定义了像< em> plus 和次。
因此,允许通过隐式提供所需操作来实现对允许哪些类型 A a TraversableOnce [A] .sum 的限制。
这只是对数字和类型类的整体工作原理的快速解释。有关更多信息,请查看math.Numeric.XisY,math.Integral和math.Fractional以及类型类的工作原理:implicit-tricks-type-class-pattern和type-class-pattern-example。