我一直在閱讀布魯諾的 TypeClasses 論文,他提到引數串列中的隱式被投影/傳播到隱式范圍中。我按照這個代碼的例子:
package theory
import cats.implicits.toShow
import java.io.PrintStream
import java.util.Date
object Equality extends App {
import cats.Eq
// assert(123 == "123")
println(Eq.eqv(123, 123).show)
implicit val out: PrintStream = System.out
def log(m: String)(implicit o: PrintStream ): Unit =
o.println(m)
def logTime(m: String)(implicit o: PrintStream): Unit =
log(s"${new Date().getTime} : $m")
}
關鍵是這段代碼不會編譯,有:
ambiguous implicit values:
both value out in object Equality of type java.io.PrintStream
and value o of type java.io.PrintStream
match expected type java.io.PrintStream
log(s"${new Date().getTime} : $m")
所以,我假設編譯器看到 2 個相同的隱式實體并抱怨。通過顯式添加作為引數傳遞的 PrintStream 作為日志的第二個引數,我能夠使編譯器靜音:
def logTime(m: String)(implicit o: PrintStream): Unit =
log(s"${new Date().getTime} : $m")(o)
這有效,但我錯過了什么嗎?為什么 logTime() 的主體內部存在混淆?我認為布魯諾暗示來自呼叫者的隱式將被投影到方法的范圍內。他的例子沒有在 log() 呼叫中添加額外的引數。為什么 scalac 將這些視為 2?我想我假設來自外部方法的隱式會“隱藏”val。不是這樣。
如果有人能解釋我為什么看到這一點,將不勝感激。
uj5u.com熱心網友回復:
回想一下,隱式引數的值是在呼叫點確定的。這就是為什么...
Equality.log("log this")
...除非將適當型別的隱式值帶入范圍,否則不會編譯。
implicit val ps: PrintStream = ...
Equality.log("log this")
的logTime()定義的代碼是一個呼叫位置的log()方法,由于它是在中定義Equality的物件,它具有implicit val out提供給它的值。但它也是implicit o從其呼叫站點傳遞的相同型別值的接收者。從而產生歧義。編譯器應該將implicit out值還是將implicit o值發送給log()方法?
現在,接收到的隱式值(來自呼叫站點)既分配給本地識別符號o,又插入到本地隱式命名空間中,這似乎有點奇怪。事實證明,Scala-3 已經修改了該行為,即使沒有新的given/using語法,您的代碼也可以編譯而不會出錯。(我假設implicit out值傳遞給log()方法而不是接收到的o值。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/401913.html
上一篇:在Scala中保存當前狀態
