根据样式指南 – 是否有一个经验法则是什么应该用于
Scala中的类型类 – 上下文绑定或隐式ev符号?
这两个例子也是如此
上下文绑定具有更简洁的函数签名,但需要使用隐式调用进行val评估:
def empty[T: Monoid,M[_] : Monad]: M[T] = { val M = implicitly[Monad[M]] val T = implicitly[Monoid[T]] M.point(T.zero) }
def empty[T,M[_]](implicit T: Monoid[T],M: Monad[M]): M[T] = { M.point(T.zero) }
我检查的大多数库(例如“com.typesafe.play”%%“play-json”%“2.6.2”)使用隐式ev
你在用什么?为什么?
解决方法
在隐式使用时需要注意的一个警告是使用依赖类型的函数.我将引用“宇航员类型宇航员指南”这本书.它查看Shapeless中的Last类,它检索HList的最后一个类型:
package shapeless.ops.hlist trait Last[L <: HList] { type Out def apply(in: L): Out }
并说:
The implicitly method from scala.Predef has this behavIoUr (this
behavior means losing the inner type member information). Compare the
type of an instance of Last summoned with implicitly:
implicitly[Last[String :: Int :: HNil]] res6: shapeless.ops.hlist.Last[shapeless.::[String,shapeless .::[Int,shapeless.HNil]]] = shapeless.ops.hlist$Last$$anon$34@20bd5df0
to the type of an instance summoned with Last.apply:
Last[String :: Int :: HNil] res7: shapeless.ops.hlist.Last[shapeless.::[String,shapeless.HNil]]]{type Out = Int} = shapeless.ops.hlist$Last$$anon$34@4ac2f6f
被隐式召唤的类型没有Out类型成员,这是一个重要的警告,并且通常为什么你会使用不使用上下文边界和隐式的召唤器模式.
除此之外,我发现这通常是一种风格问题.是的,隐式地可能会稍微增加编译时间,但是如果你有一个隐式的富应用程序,你很可能在编译时“感觉”两者之间的差异.
而且更个人而言,有时候隐式写[M [T]]比使方法签名更长一些感觉更“丑陋”,并且当您使用命名字段明确声明隐式时,读者可能会更清楚.