隐式转换
隐式转换(Implicit Conversion)由类 scala.Conversion 的 given 实例定义。 该类在包 scala 中的定义如下:
abstract class Conversion[-T, +U] extends (T => U) {
def apply (x: T): U
}
例如,下面是从 String 到 Token 的隐式转换:
given Conversion[String, Token] with {
def apply(str: String): Token = new KeyWord(str)
}
使用别名可以更简洁的表示为:
given Conversion[String, Token] = new KeyWord(_)
在以下三种情况下,编译器会自动应用隐式转换:
- 如果表达式
e具有类型T,且T不符合表达式的预期类型S。 - 在选择
e.m中,e的类型为T,但T没有定义成员m。 - 在应用
e.m(args)中,e的类型为T,T定义了一些名为m的成员,但这些成员都不能应用于参数args。
在第一种情况下,编译器查找将类型 T 映射至类型 S 的 scala.Conversion given 实例。 在第二和第三种情况下,编译器查找 scala.Conversion 的 given 实例,该实例将类型 T 映射至定义了成员 m,(在 args 存在时)并且 m 可以应用于 args。如果找到了这样的实例 C,则表达式 e 被替换为 C.apply(e)。
示例
Predef包含“自动装箱”转换,把基本数值类型映射到java.lang.Number的子类型。 例如,从Int到java.lang.Integer的转换可以这样定义:given int2Integer: Conversion[Int, java.lang.Integer] = java.lang.Integer.valueOf(_)- “magnet”模式有时用于表示一个方法的多个变体。除了定义方法的重载版本,还可以让方法接受一个或多个特殊定义的“magnet”类型的参数, 各种参数类型可以转换为这些参数类型。例如:
object Completions { // The argument "magnet" type enum CompletionArg { case Error(s: String) case Response(f: Future[HttpResponse]) case Status(code: Future[StatusCode]) } object CompletionArg { // conversions defining the possible arguments to pass to `complete` // these always come with CompletionArg // They can be invoked explicitly, e.g. // // CompletionArg.fromStatusCode(statusCode) given fromString : Conversion[String, CompletionArg] = Error(_) given fromFuture : Conversion[Future[HttpResponse], CompletionArg] = Response(_) given fromStatusCode: Conversion[Future[StatusCode], CompletionArg] = Status(_) } import CompletionArg.* def complete[T](arg: CompletionArg) = arg match { case Error(s) => ... case Response(f) => ... case Status(code) => ... } }这些步骤比简单地重载
complete复杂,但如果正常重载不可用(如上面的情况,因为我们不能有两个重载方法接受Future[...]参数), 或者正常重载会导致重载组合数量爆炸,那么这种模式也是有用的。