2016-12-02 6 views
0

フレームワークのIDタイプの抽象化をサポートしようとしています。ここでは例:予想通り、この作品オプションのスカラーの基本型の変換

val fooString = new Foo[String] 
val fooLong = new Foo[Long] 
val fooInt = new Foo[Int] 


fooString.getID("asdf") // "asdf":String 
fooLong.getID("1234") // 1234:Long 
fooInt.getID("1234") // 1234:Int 
fooInt.getID("asdf") // java.lang.NumberFormatException 

object AmINecessary { 
    case class StringConverter[T](op: String => T) 
    implicit val toInt = new StringConverter[Int](_.toInt) 
    implicit val toLong = new StringConverter[Long](_.toLong) 
} 

class Foo[ID] { 
    // ID can be String, Long, or Int 
    import AmINecessary._ 
    // If ID is string, return string, otherwise convert to ID 
    def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id) 
} 

これは次のように使用されています。私の質問は以下のとおりです。

  1. それは悪いを感じているに分岐し、その後nullにそれをデフォルトによって、オプションの暗黙のを使用して。それを達成するスケーラの方法は何ですか?
  2. 文字列の暗黙の変換をlongまたはintに記述することは本当に必要ですか?

答えて

1

私は最良の選択肢は、暗黙的にStringConverter[String]を追加し、デフォルトのnullの値を削除することです。 あなたのfooStringが他のすべてのタイプのためにClassCastExceptionを危険にさらすことなく動作する方法。

object AmINecessary { 
    case class StringConverter[T](op: String => T) 
    implicit val toInt = new StringConverter[Int](_.toInt) 
    implicit val toLong = new StringConverter[Long](_.toLong) 
    implicit val idConverter = new StringConverter[String](identity) 
} 

class Foo[ID] { 
    import AmINecessary.StringConverter 

    def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id) 
} 

あなたの質問2については、型クラスのアプローチは本当に必要な(しかし、ここには暗黙の変換が存在しないことに注意してください)ではありません。

abstract class Foo[ID] { 
    def getID(id: String): ID 
} 

class FooInt extends Foo[Int] { 
    def getID(id: String) = id.toInt 
} 

class FooLong extends Foo[Long] { 
    def getID(id: String) = id.toLong 
} 

class FooString extends Foo[String] { 
    def getID(id: String) = id 
} 
+0

2番目の例は、私が暗黙のうちに戦った後にやったことです。偉大な気分にはなりませんが、暗黙の混乱や仕事よりも優れています。 – rapidninja

0

1)暗黙のヌルをデフォルトについて、あなただけの可能性:

object Unsafe { 
    implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T]) 
} 

2)それは良いアイデアのように思えません。まず、asInstanceOfを隠しているため、安全でない操作(潜在的なランタイム例外)です。第二に、より明示的な変換はより良いことです。

あなたには、いくつかの複雑な変換が予想される場合 - それはあなたのgetIDメソッドからオプションを返すために良いでしょう:

def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id)) 

ただし、デフォルトパラメータは、いずれかの最善のアプローチではありませんが。コンパイル時にエラーが発生して、ユーザが自分のコンバータを書くか、または一般的にasInstanceOfを明示的に実行する必要があります。それがために働くだろう唯一のタイプがStringであるとして、あなたの具体的な場合にはasInstanceOf

はあまり意味がありません、getId[String]のように、そうしてgetIdを呼び出すのポイントは何ですか?

+0

nullコンバータのアイデア:可能なIDのタイプは3つだけです。私がStringToStringを追加しようとすると、あいまいな解決法が嫌になりました。なんらかの理由で、Jasper-Mのバージョンが動作しています。 – rapidninja

関連する問題