Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KotlinでPhantom Type #kotlin_sansan

KotlinでPhantom Type #kotlin_sansan

第2回Kotlin勉強会 @ Sansan

C057726b79d9eaed10c136794ef833fa?s=128

Jumpei Yamamoto

March 24, 2016
Tweet

Transcript

  1. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > KotlinでPhantom  Type

    第2回Kotlin勉強会  @Sansan   #kotlin_̲sansan   2016.  3.  24   @boohbah  
  2. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > ⾃自⼰己紹介 -

    ⼭山本純平   - Sansan株式会社  Eight事業部     - EightのAndroidアプリの開発   - twitter:  @boohbah   - github:  https://github.com/yamamotoj  
  3. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > DroidKaigi  2016

  4. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 4

  5. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Eightの新機能「オンライン名刺刺交換」 -

    もう紙の名刺刺はいらない!   - NearByで周囲のEightユー ザーを検索索   - 複数のユーザー間でも名刺刺 交換ができる
  6. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 6

  7. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 7

  8. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 8

  9. Copyright  ©  Sansan,  Inc.  All  rights  reserved.

  10. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 10 KotlinͰ Type

  11. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Phantom Type

    (༓ྶܕ) - Πϯελϯεͷঢ়ଶΛܕύϥϝʔλͰ࣋ͭ͜ͱʹΑͬ ͯɺঢ়ଶͷνΣοΫΛίϯύΠϧ࣌ʹߦ͏ɻ - ঢ়ଶΛද͢ܕύϥϝʔλ͸࣮ࡍʹ࢖ΘΕΔ͜ͱ͕ͳ ͘ɺίϯύΠϧ࣌ʹফ͑ͯ͠·͏ɻ
  12. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 実際に⾒見見てみましょう sealed

     class  State  {          class  NotReady  :  State()          class  Ready  :  State()   }   data  class  Data<T  :  State>(val  a:  Int)  {   }   これが  Phantom  Type 型パラメータは実⾏行行時に消 去されるため、Stateクラ スが使⽤用されることはない
  13. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 引数で振り分け fun

     show(data  :Data<NotReady>)  =            print(“Not  ready!!”)   fun  show(data:  Data<Ready>)  =          print(“ready!!”)   fun  bar(data:  Data<Ready>)  =          print(“bar!”) val  d1  =  Data<NotReady>(2)   show(d1)  //  -­‐>  Not  ready!!   bar(d1)    //  ίϯύΠϧΤϥʔ   val  d2  =  Data<Ready>(2)   show(d2)  //  -­‐>  ready  !!   bar(d2)    //  -­‐>  bar!  
  14. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 拡張関数と併⽤用する fun

     Data<State.NotReady>.ready()  =  Data<State.Ready>(a)   fun  Data<State.Ready>.say()  =  print(“I’m  ready!!”)    val  d1  =  Data<State.NotReady>(2)    val  d2  =  d1.ready()  //  Data<State.Ready>   d1.say()      //  ίϯύΠϧΤϥʔ   d2.ready()  //  ίϯύΠϧΤϥʔ   d2.say()      //  -­‐>  I;m  ready!!              d1  ==  d2    //  True
  15. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 利利⽤用シーン

  16. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 例例えば簡単なSQL⽂文を出⼒力力するDSLを考えてみる Query

             .select("*")          .from("Person")          .where("ID  =  1")          .print()   //  -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;  
  17. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > クラスと状態の定義 //

     -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;   sealed  class  Status  {          class  From  :  Status()   //  From۟ΛೖྗͰ͖Δঢ়ଶ          class  Where  :  Status()    //  Where۟ΛೖྗͰ͖Δঢ়ଶ          class  Print  :  Status()    //  ݁ՌΛग़ྗͰ͖Δঢ়ଶ   }   //  Queryੜ੒Ϋϥεͷఆٛ   class  Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  
  18. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > メソッドの定義 class

     Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  {   }  
  19. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > メソッドの定義 class

     Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  {          companion  object  {                  fun  select(column:  String)  =                              Query<Status.From>(column,  "",  "")          }   }   Query<Status.From>型   のオブジェクトを⽣生成
  20. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > メソッドの定義 class

     Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  {          companion  object  {                  fun  select(column:  String)  =                              Query<Status.From>(column,  "",  "")          }   }   fun  Query<Status.From>.from(tableName:  String)  =                  Query<Status.Where>(this.column,  tableName,  this.predicate)   Query<Status.Where>型   のオブジェクトを⽣生成 Query<Status.From>型   からしか呼び出せない
  21. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > メソッドの定義 class

     Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  {          companion  object  {                  fun  select(column:  String)  =                              Query<Status.From>(column,  "",  "")          }   }   fun  Query<Status.From>.from(tableName:  String)  =                  Query<Status.Where>(this.column,  tableName,  this.predicate)   fun  Query<Status.Where>.where(predicate:  String)  =                  Query<Status.Print>(this.column,  this.tableName,  predicate)   Query<Status.Print>型のオブジェクトを⽣生成 Query<Status.Where>型   からしか呼び出せない
  22. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > メソッドの定義 class

     Query<T  :  Status>(                  val  column:  String,                  val  tableName:  String,                  val  predicate:  String)  {          companion  object  {                  fun  select(column:  String)  =                              Query<Status.From>(column,  "",  "")          }   }   fun  Query<Status.From>.from(tableName:  String)  =                  Query<Status.Where>(this.column,  tableName,  this.predicate)   fun  Query<Status.Where>.where(predicate:  String)  =                  Query<Status.Print>(this.column,  this.tableName,  predicate)   fun  Query<Status.Print>.print()  =                  "SELECT  $column  FROM  $tableName  WHERE  $predicate  ;" Query<Status.Print>型   からしか呼び出せない
  23. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > 結果 Query

             .select(“*”)          //  Query<Status.From>          .from(“Person")    //  Query<Status.Where>          .where("ID  =  1”)  //  Query<Status.Print>            .print()   //  -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;  
  24. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > まとめ -

    Kotlinでも型レベルプログラミング!
  25. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > おまけ

  26. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お気に⼊入りの拡張関数 fun

     <T  :  Any>  T.log(                  tag:  String  =  "my-­‐debug",                  to_string:  (T)  -­‐>  String  =  {  it.toString()  }   ):  T  {          Log.d(tag,  to_string(this))          return  this   }
  27. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お気に⼊入りの拡張関数 fun

     <T  :  Any>  T.log(                  tag:  String  =  "my-­‐debug",                  to_string:  (T)  -­‐>  String  =  {  it.toString()  }   ):  T  {          Log.d(tag,  to_string(this))          return  this   } fun  getHoge()  =  A().let{  transform(it)  }.B()  
  28. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お気に⼊入りの拡張関数 fun

     <T  :  Any>  T.log(                  tag:  String  =  "my-­‐debug",                  to_string:  (T)  -­‐>  String  =  {  it.toString()  }   ):  T  {          Log.d(tag,  to_string(this))          return  this   } fun  getHoge()  =  A().log().let{  transform(it)  }.B()   Single  Expression形式でもlogを出せる
  29. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お気に⼊入りの拡張関数 fun

     <T  :  Any>  T.log(                  tag:  String  =  "my-­‐debug",                  to_string:  (T)  -­‐>  String  =  {  it.toString()  }   ):  T  {          Log.d(tag,  to_string(this))          return  this   } fun  getHoge()  =  A().log(){  “a:”  +  it.toString()  }   .let{  transform(it)  }.B()   任意の⽂文字列列に変換可能
  30. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > お気に⼊入りの拡張関数 fun

     <T  :  Any>  T.log(                  tag:  String  =  "my-­‐debug",                  to_string:  (T)  -­‐>  String  =  {  it.toString()  }   ):  T  {          Log.d(tag,  to_string(this))          return  this   } fun  getHoge()  =  A().log(“my_tag”){  “a:  $it”  }   .let{  transform(it)  }.B()   タグも変更更できる
  31. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > おまけ2

  32. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Raw  Textリテラル便便利利

    val  json  =  """   {          "name":  yamamotoj,          "url":  "https://github.com/yamamotoj",   }   """ //  Java   String  json  =  "{\n"  +                  "        \"name\":  yamamotoj,\n"  +                  "        \"url\":  \"https://github.com/yamamotoj\",\n"  +                  "}\n";  
  33. $PQZSJHIU˜4BOTBO *OD"MMSJHIUTSFTFSWFE  4BOTBO͸Ұॹʹ৽͍͠Ձ஋Λ࡞͍ͬͯ͘ ஥ؒΛ͕͍ͯ͞͠·͢ɻ 3VCZ 3VCZPO3BJMT ʢ8FCΞϓϦέʔγϣϯʣ $ɼ"41/&5.7$ ʢ8FCΞϓϦέʔγϣϯʣ

    J04"OESPJEΞϓϦ   ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ   ໊ࢗσʔλԽ෼ࢄॲཧγεςϜ   ๏ਓ޲໊͚ࢗ؅ཧαʔϏεʮ4BOTBOʯ   ๏ਓ޲໊͚ࢗ؅ཧαʔϏε ʮ4BOTBOʯ   ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ ΤϯδχΞืूத 4BOTBO࠾༻ ݕࡧ SFDSVJU!TBOTBODPN·Ͱ ͓ؾܰʹ͝࿈བྷ͍ͩ͘͞ɻ ڵຯͷ͋Δํ͸
  34. Copyright  ©  Sansan,  Inc.  All  rights  reserved. > Thank  you

    34