假设:
install.packages("Rmpfr" , INSTALL_opts = "--with-mpfr-include=/path/to/mpfr/include")
install.packages("Rmpfr" , configure.args = "--with-mpfr-include=/path/to/mpfr/include")
install.packages("Rmpfr" , configure.vars = "--with-mpfr-include=/path/to/mpfr/include")
和一个类型:
scala> sealed trait Father
defined trait Father
scala> case object Son extends Father
defined object Son
接下来,我定义了函数scala> trait Foo[A]
defined trait Foo
,据我所知,它希望类型参数f
是A
的子类,并且有一个类型类Father
的实例。
Foo
然后,我定义了一个实例:
scala> def f[A <: Father : Foo](x: Father): String = x.toString
f: [A <: Father](x: Father)(implicit evidence$1: Foo[A])String
最后我称之为:
scala> implicit val fooFather = new Foo[Father] {}
fooFather: Foo[Father] = $anon$1@4f25b795
但是,在我看来,scala> f(Son)
res0: String = Son
可以写成:
f
是否有编写上述函数def f[A <: Father](x: Father)(implicit ev: Foo[A]): String = x.toString
的首选方法?而且,它们之间有区别吗?
答案 0 :(得分:3)
不,他们是完全一样的。
上下文界限,btw是Foo
中def f[A <: Father : Foo]
被调用的方式,有一个问题。如果在方法的主体中你需要引用隐式参数,你最终需要使用implicitly[Foo[A]]
,这很不方便,即
def f[A <: Father : Foo](x: Father): String = {
implicitly[Foo[A]].ifFooHadAMethod // couldn't think of a better example :)
x.toString
}
这就是为什么在很多代码中人们使用
def f[A <: Father : Foo](x: Father)(implicit ev:Foo[A]): String = {
ev.ifFooHadAMethod // couldn't think of a better example :)
x.toString
}
我个人更喜欢第二种情况,只要我需要引用隐式参数,否则我更喜欢使用上下文边界。