Scala有许多可用作类型的特征,例如Ordered
包中的Numeric
和scala.math
。
例如,我可以使用Ordered
编写一个通用方法,如下所示:
def f[T <% Ordered[T]](a: T, b: T) = if (a < b) a else b
我想与Numeric
做类似的事情,但这不起作用:
def g[T <% Numeric[T]](a: T, b: T) = a * b
为什么Ordered
和Numeric
之间存在明显的差异?
我知道还有其他方法可以做到这一点,以下方法可行(使用上下文绑定):
def g[T : Numeric](a: T, b: T) = implicitly[Numeric[T]].times(a, b)
但这看起来比仅仅使用*
乘以两个数字更复杂。为什么Numeric
特征不包含*
等方法,而Ordered
包含<
等方法?
我知道还有Ordering
,您可以像Numeric
一样使用def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
,另请参阅this answer:
{{1}}
答案 0 :(得分:12)
如果从隐式Numeric [T]
导入符号运算符,则它们可用def g[T : Numeric](a: T, b: T) = {
val num = implicitly[Numeric[T]]
import num._
a * b
}
如果你想只使用一个操作符,这显然有点笨拙,但在非平凡的情况下,导入的开销并不是那么好。
如果没有显式导入,为什么运营商不可用?默认情况下,默认情况下使隐含可见的常见考虑因素在这里适用,可能更常见,因为这些运算符被广泛使用。
答案 1 :(得分:5)
Ordered
只是一些返回Int
或Boolean
的简单拉皮条方法,因此不需要任何类型技巧。
Numeric
具有根据所使用的确切子类返回不同类型的方法。因此,Ordered
只是标记特征,Numeric
是一个功能齐全的类型。
要让您的操作员回来,您可以在lhs操作数上使用mkNumericOps
(在Numeric
中定义)。
<强>更新强>
Miles非常正确,mkNumericOps
是隐含的,所以只需导入Numeric实例就可以让你恢复所有魔法......
答案 2 :(得分:5)
你可以通过这样做来减少Miles的解决方案只使用1个额外的行:
添加从A : Numeric
到Numeric[A]#Ops
object Ops {
implicit def numeric[A : Numeric](a: A) = implicitly[Numeric[A]].mkNumericOps(a)
}
然后将其纳入您方法的范围
def g[T : Numeric](a: T, b: T) = {
import Ops.numeric
a * b
}
有关详细信息,请参阅Scala ticket 3538。