Scala implicit

5339 ワード

Scala implicit
implicitの基本的な意味
Scalaにはimplicitというキーワードがありますが、これまでこの商品が何をしているのか分からなかったので、今日整理しました.
まず例を見てみましょう
def display(input:String):Unit = println(input)
display関数の定義はStringタイプのパラメータを受け入れるだけであり、display("any string")のような関数を呼び出すのは問題ないことがわかります.ただし、呼び出しdisplay(1)のようなパラメータがStringタイプでない場合、コンパイルはエラーになります.
display関数をIntタイプのパラメータにも対応させたい場合は、def display(input:Int):Unit = println(input)のような関数を再定義するほか、同じ役割ドメイン内でimplicitキーワードで暗黙的な変換関数を定義することもできます.例コードは次のとおりです.
object ImplicitDemo {

  def display(input:String):Unit = println(input)

  implicit def typeConvertor(input:Int):String = input.toString

  implicit def typeConvertor(input:Boolean):String = if(input) "true" else "false"

//  implicit def booleanTypeConvertor(input:Boolean):String = if(input) "true" else "false"


  def main(args: Array[String]): Unit = {
    display("1212")
    display(12)
    display(true)
  }

}

2つの暗黙的変換関数を定義しました.
  implicit def typeConvertor(input:Int):String = input.toString

  implicit def typeConvertor(input:Boolean):String = if(input) "true" else "false"

これによりdisplay関数はString,Int,Booleanタイプのパラメータを受け入れることができる.上記の例のアノテーションの行に注意してください.アノテーションの行を削除すると、実行時に二義性が現れます.
Error:(18, 13) type mismatch;
 found   : Boolean(true)
 required: String
Note that implicit conversions are not applicable because they are ambiguous:
 both method typeConvertor in object ImplicitDemo of type (input: Boolean)String
 and method booleanTypeConvertor in object ImplicitDemo of type (input: Boolean)String
 are possible conversion functions from Boolean(true) to String
    display(true)
            ^

結論は次のとおりです.
暗黙的変換関数とは、同じ役割ドメインの下で、指定された入力タイプが自動的に指定された戻りタイプに変換される関数です.この関数は、関数名に関係なく、パラメータ名に関係なく、パラメータタイプおよび戻りタイプにのみ関係します.同じ役割ドメインであることに注意してください.
implicitの応用
scala関数のいくつかの組み込み定義を簡単に開くことができます.例えば、私たちが最もよく使うmap関数の->記号はphpなどの言語に似ています.しかし、実際には->は確かにscalaソースコードのPredefに位置するArrowAssocクラスの方法である.scalaで.このクラスの定義は次のとおりです.
  final class ArrowAssoc[A](val __leftOfArrow: A) extends AnyVal {
    // `__leftOfArrow` must be a public val to allow inlining. The val
    // used to be called `x`, but now goes by `__leftOfArrow`, as that
    // reduces the chances of a user's writing `foo.__leftOfArrow` and
    // being confused why they get an ambiguous implicit conversion
    // error. (`foo.x` used to produce this error since both
    // any2Ensuring and any2ArrowAssoc pimped an `x` onto everything)
    @deprecated("Use `__leftOfArrow` instead", "2.10.0")
    def x = __leftOfArrow

    @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(__leftOfArrow, y)
    def →[B](y: B): Tuple2[A, B] = ->(y)
  }
  @inline implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
def ->[B] (y :B)が実際にはTuple2[A,B]タイプを返しているのを見ました.Mapを定義します.
scala> val mp = Map(1->"game1",2->"game_2")
mp: scala.collection.immutable.Map[Int,String] = Map(1 -> game1, 2 -> game_2)

ここで1->"game1"は実は1.->("game_1")の略です.ここでどうして整数タイプ1に->方法を持たせることができようか.ここでは実はany2ArrowAssoc暗黙関数が機能しており,ここで受けるパラメータ[A]は汎用的であるためintも例外ではない.呼び出しは、整数の1 implicitをArrowAssoc(1)に変換して構築方法を見て、1を__leftOfArrowとして転送することです.->方法の真の実装は、Tuple 2タイプのオブジェクト(__leftOfArrow,y )(1, "game_id")に等価であることであり、これは典型的な暗黙的な変換アプリケーションである.
他にも似たような暗黙的な変換がたくさんあります.すべてPredefです.scala:たとえば、Int、Long、DoubleはAnyValのサブクラスであり、この3つのタイプの間には継承された関係がなく、直接相互に変換することはできません.Javaでは、Longを宣言するときに末尾にLを付けてlongであることを宣言します.しかしscalaでは、それほど考える必要はありません.
scala> val l:Long = 10
l: Long = 10

これがimplicit関数であり,scalaタイプ推定の一部でもあり,柔軟で簡潔である.実はここで呼び出されたのは:
val l : Long = int2long(10)

より強力な機能
既存のクラスライブラリに機能を追加する方法の1つで、javaではツールクラスや継承方式でしか実現できませんが、scalaでは暗黙的な変換方式で実現することもできます.
暗黙パラメータ
例を見てみましょう.
object ImplictDemo {

  object Context{
    implicit val ccc:String = "implicit"
  }


  object Param{
    def print(content:String)(implicit prefix:String){
      println(prefix+":"+content)
    }
  }

  def main(args: Array[String]) {
    Param.print("jack")("hello")

    import Context._
    Param.print("jack")
  }

}

プログラムの実行結果は次のとおりです.
hello:jack
implicit:jack

暗黙的変換拡張
import java.io.File

import scala.io.Source

class RichFile(val file:File){
  def read = Source.fromFile(file.getPath()).mkString
}

object Context{
  implicit def file2RichFile(f:File)= new RichFile(f)
}

object ImplictDemo {

  def main(args: Array[String]) {
    import Context.file2RichFile
    println(new File("f:\\create.sql").read)
  }

}

上のコードで呼び出されるreadメソッドは、実はRichFileで定義されているreadメソッドです.
最後のまとめ:
  • 暗黙変換関数の同じscopにパラメータと戻り値が全く同じ2つのimplicit関数が存在しないことを覚えています.
  • 暗黙変換関数は入力タイプのみを気にし、タイプを返します.
  • 暗黙的変換はscalaの文法の柔軟さと簡潔さの重要な構成部分
  • である.
    参考資料
  • http://blog.csdn.net/oopsoom/article/details/24643869