Scalaモード:パイプオペレータ
に質問
私たちがコードを書くのは左から右へ書くのが好きで、どんなに流暢で、どんなに順調ですか.
このコードを考慮すると、いくつかのデータのjson形式を返します.多分こう書きます.
私はデータを取得する式
左から右へ書くことができなくて、流暢ではありません!
データオブジェクトにtoJsonメソッドがあれば、左から右に
単純配管
昨夜UNIX shellのパイプ:
実は、ScalaのDSL能力を利用して、自分で実現することもできます.コードを見てください:
カスタマイズされた|:オペレータ.Scalaでは、メソッド名として記号を使用することができます.オペレータのように、このメソッドのthisパラメータが右側にあることを示すコロン接尾辞が使用されます.実際にコンパイラによって
残念なことに、複数のパイプを簡単に接続することはできません.data|:Json|:Printlnはできません.このオペレータは右結合されているので、呼び出し順序は左から左で、左から右ではありません.かっこを付けない限り:
行頭にかっこをつけるのは避けられません.流暢ではありません.
れんぞくかんろ
方法はまだありますが、正常な左結合オペレータをなんとか運用します.任意のオブジェクトを拡張できればいいです.では、任意のオブジェクトにパイプオペレータを拡張しましょう.究極の実装コード:
実はコンパイラに翻訳されて
完全な例
フルコードはこちらで提供しておりますので、REPLまたはIDEのScala WorkSheetで実行してください.
(Update:
Rubyのような動的言語も似たように拡張できますが、こんなに簡潔にはできないかもしれません.大体次のように書くことができます.
誰かRubyでもっと簡潔に実現できたら教えてください!
私たちがコードを書くのは左から右へ書くのが好きで、どんなに流暢で、どんなに順調ですか.
このコードを考慮すると、いくつかのデータのjson形式を返します.多分こう書きます.
def getyou() = {
Json(Map("a"->1, "b"->2))
}
私はデータを取得する式
Map("a"->1, "b"->2)
を書いて、jsonに戻ることを思い出して、そこで行頭に移動して、Json(
と書いて、更に行尾に移動して、)
と書きます.左から右へ書くことができなくて、流暢ではありません!
データオブジェクトにtoJsonメソッドがあれば、左から右に
data.toJson
と直接書くことができ、スムーズです!しかし、一般的な相手にtoJsonメソッドがない場合はどうしますか?単純配管
昨夜UNIX shellのパイプ:
a | b | c
を思い出しました.もしScalaにこの文法が内蔵されていたらどんなにいいだろう.実は、ScalaのDSL能力を利用して、自分で実現することもできます.コードを見てください:
object Json {
def |:(obj: Map[_, _]) = {
val conc = obj.map{p => " " + p._1 + ": " + p._2}.mkString(",
")
"{
" + conc + "
}"
}
}
Map("a"->1, "b"->2) |: Json
カスタマイズされた|:オペレータ.Scalaでは、メソッド名として記号を使用することができます.オペレータのように、このメソッドのthisパラメータが右側にあることを示すコロン接尾辞が使用されます.実際にコンパイラによって
Json.|:(Map("a"->1, "b"->2))
に翻訳され、左から右へスムーズにコードが書けるようになりました残念なことに、複数のパイプを簡単に接続することはできません.data|:Json|:Printlnはできません.このオペレータは右結合されているので、呼び出し順序は左から左で、左から右ではありません.かっこを付けない限り:
object Println {
def |:(obj: Any) = println(obj)
}
(Map("a"->1, "b"->2) |: Json) |: Println
行頭にかっこをつけるのは避けられません.流暢ではありません.
れんぞくかんろ
方法はまだありますが、正常な左結合オペレータをなんとか運用します.任意のオブジェクトを拡張できればいいです.では、任意のオブジェクトにパイプオペレータを拡張しましょう.究極の実装コード:
implicit def pipify[T](t: T) = new {
def |[R](f: T=>R): R = f(t)
}
def json(obj: Map[_, _]) = obj |: Json
Map("a"->1, "b"->2) | json | println
実はコンパイラに翻訳されて
pipify(pipify(Map("a"->1, "b"->2)).|(json)).|(println)
ハハ、気絶しましたか?完全な例
フルコードはこちらで提供しておりますので、REPLまたはIDEのScala WorkSheetで実行してください.
val data = Map("a"->1, "b"->2)
object Json {
def |:(obj: Map[_, _]) = {
val conc = obj.map{p => " " + p._1 + ": " + p._2}.mkString(",
")
"{
" + conc + "
}"
}
}
def json(obj: Map[_, _]) = obj |: Json
object Println {
def |:(obj: Any) = println(obj)
}
implicit def piping[T](t: T) = new {
def |[R](f: T=>R): R = f(t)
}
(data |: Json) |: Println
data | json | println
(Update:
|>
と書かれている流派を発見し、とにかく使用者自選)Rubyのような動的言語も似たように拡張できますが、こんなに簡潔にはできないかもしれません.大体次のように書くことができます.
#a
#
a.pipe b
#
a.pipe(b).pipe(c)
誰かRubyでもっと簡潔に実現できたら教えてください!