Scala隐式参数与隐式调用

14

我是 Scala 的新手,当我查看不同的项目时,发现有两种处理隐式参数的方式。

scala]]>def sum[A](xs:List[A])(implicit m:Monoid[A]): A = xs.foldLeft(m.mzero)(m.mappend)
sum:[A](xs:List[A])(implicit m:Monoid[A])A
并且
scala]]>def sum[A:Monoid](xs:List[A]): A ={
     val m = implicitly[Monoid[A]]
     xs.foldLeft(m.mzero)(m.mappend)
   }
sum:[A](xs:List[A])(implicit evidence$1:Monoid[A])A

根据两个函数的类型,它们是匹配的。它们之间有什么区别?为什么你想使用隐式转换而不是隐式参数?在这个简单的例子中,感觉更冗长。

当我在REPL中运行上述代码并使用没有隐式的内容时,我会得到以下错误。

使用隐式参数

<console>:11: error: could not find implicit value for parameter m: Monoid[String]

使用隐含的 "and" 和一个 Monoid:

<console>:11: error: could not find implicit value for evidence parameter of type Monoid[String]
1个回答

15
在某些情况下,隐式形参并未直接在以其为参数的方法体中使用。相反,它只是成为一个隐式val传递给另一个需要相同类型(或兼容类型)隐式形参的方法。在这种情况下,没有显式的隐式参数列表是比较方便的。
在其他情况下,上下文界定符号被认为是美学上的优势,即使实际参数是必需的,因此必须使用implicitly方法来获得它也被认为是更可取的。
鉴于两者之间没有语义差异,选择基于相当主观的标准。
你可以自由选择。最后请注意,从一个转换到另一个不会破坏任何代码,也不需要重新编译(虽然我不知道SBT是否足够歧视以不重新编译可以看到已更改定义的代码)。

1
请注意,从一个参数更改为另一个参数不会破坏任何代码,也不需要重新编译:这在技术上是不正确的。显式指定隐式参数作为命名参数是完全正确的(尽管不常见)。因此,您可以执行sum(List(1,2,3))(m=someMonoidInstance)。将声明中的隐式参数替换为上下文界定将会将隐式参数名称从“m”更改为类似于“evidence$1”的内容,从而破坏上述调用。参数名称(包括隐式参数)是界面的一部分,既有好处也有坏处。吹毛求疵,但仍然很重要。 - Régis Jean-Gilles
好的,好的... 这是相当苛刻的要求! - Randall Schulz
在其他情况下,上下文绑定符号(严格来说是一种明显的隐式参数的语法糖)被认为具有美学价值,即使实际参数是必需的,因此必须使用隐式方法来获取它。 - RoyalCanadianKiltedYaksman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接