隐式定义,尤其是转换。
例如,假设一个函数将格式化输入字符串以适应大小,方法是将其中间替换为“...”:
def sizeBoundedString(s: String, n: Int): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
您可以将它与任何字符串一起使用,当然,也可以使用 toString 方法来转换任何内容。但你也可以这样写:
def sizeBoundedString[T](s: T, n: Int)(implicit toStr: T => String): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
然后,您可以通过以下方式传递其他类型的类:
implicit def double2String(d: Double) = d.toString
现在您可以通过双精度调用该函数:
sizeBoundedString(12345.12345D, 8)
最后一个参数是隐式的,并且由于隐式 de 声明而被自动传递。此外,“s”在 sizeBoundedString 内被处理为字符串,因为从它到字符串的隐式转换。
这种类型的隐式更好地定义为不常见的类型,以避免意外的转换。你也可以显式传递一个转换,它仍然会在 sizeBoundedString 内部隐式使用:
sizeBoundedString(1234567890L, 8)((l : Long) => l.toString)
你也可以有多个隐式参数,但是你必须要么全部传递,要么不传递任何一个。还有一种隐式转换的快捷语法:
def sizeBoundedString[T <% String](s: T, n: Int): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
这个用法完全一样。
隐式可以有任何值。例如,它们可用于隐藏图书馆信息。以下面的例子为例:
case class Daemon(name: String) {
def log(msg: String) = println(name+": "+msg)
}
object DefaultDaemon extends Daemon("Default")
trait Logger {
private var logd: Option[Daemon] = None
implicit def daemon: Daemon = logd getOrElse DefaultDaemon
def logTo(daemon: Daemon) =
if (logd == None) logd = Some(daemon)
else throw new IllegalArgumentException
def log(msg: String)(implicit daemon: Daemon) = daemon.log(msg)
}
class X extends Logger {
logTo(Daemon("X Daemon"))
def f = {
log("f called")
println("Stuff")
}
def g = {
log("g called")(DefaultDaemon)
}
}
class Y extends Logger {
def f = {
log("f called")
println("Stuff")
}
}
在此示例中,在 Y 对象中调用“f”会将日志发送到默认守护程序,并在 X 的实例上将日志发送到守护程序 X 守护程序。但是在 X 的实例上调用 g 会将日志发送到显式给定的 DefaultDaemon。
虽然这个简单的示例可以用重载和私有状态重写,但隐式不需要私有状态,并且可以通过导入进入上下文。