2017-02-08 2 views
1

興味は:コール.toDouble [ダブル]

例えば
def toDouble(any: Any): Option[Double] = // { if any has a .toDouble method call it else return None } 

を、INT、文字列は、ロング全て.toDouble方法があります。それが存在すれば(たとえ非プリミティブ型であっても)呼び出されたいのですが。

理想的にはあなたは、パターンマッチングを使用することができ、この(最初にすべてを.toString'ingなし)

def toDouble(any: Any): Option[Double] = { 
    case any.hasToDouble => Try(any.toDouble).toOption 
    case _ => None 
} 
+0

http://www.scala-lang.org/api/current/scala/math/Numeric.htmlを見てください。 – cchantep

+0

他のタイプ(特にString)には、.toDoubleメソッドもあります。 – user451151

+0

@ user451151 StringにはtoDoubleはありません。このメソッドは、コンパイル時にのみ解決できる暗黙的に提供されます。コンパイル時のタイプがなければ、リフレクションを使う必要があります。 – puhlen

答えて

1
def toDouble(a: Any): Option[Double] = try { 
    if (a == null) None else { 
     Some(a.toString.toDouble) 
    } 
    } catch { 
    case scala.util.control.NonFatal(e) => None 
    } 
+0

.toStringを使用せずにすべてを行う方法はありますか?私は数十億のレコードでこれを実行します。可能であればtoStringを避けるのが大好きです。 – user451151

+4

'Any'はコードの匂い/悪いデザインのヒントです – cchantep

+0

合意されましたが、(あなたに渡された型があなたのコントロールから外れている)時には、周囲には素晴らしい方法はありません。 (もしあなたの提案があれば、私はすべての耳になります!) – user451151

3

のようなもの。これには、変換がどのように行われるかをより明示的に制御できるという追加の利点があります。 (例えば、追加の文字列解析を試してみたかった場合)

def toDouble(any: Any): Option[Double] = { 
    any match { 
    case n:Int => Some(n.toDouble) 
    case n:Long => Some(n.toDouble) 
    case n:Double => Some(n.toDouble) 
    case s:String => Try(s.toDouble).toOption 
    case _ => None 
    } 
} 
+1

これについても考えましたが、型のパターンマッチに 'Any'を使う考えは致命的です。 –

+0

ええ、これは私が現在やっていることです。問題は保守です。.toDoubleを持つカスタムオブジェクトがいくつか渡されています。手動でそれらのケースを追加する必要があります。私がプログラムで.toDoubleをチェックし、それを呼び出そうとしたいと考えていました。 – user451151

+0

これは私が狂っていないことを確認します!ありがとうございました。 – user451151

4

あなたは

def doubleFromAny(in: Any): Option[Double] = { 
    Try{in.asInstanceOf[{def toDouble: Double}].toDouble}.toOption 
} 

を使用することができますこれに伴う問題は、暗黙を通じて提供される任意のtoDoubleが動作しません(その文字列"4.5"が希望ですあなたにNoneを与える)。私はまた、パフォーマンスが上手くいかないことを期待しています。

最後に、可能なタイプを特定し、Jon Andersonの答えを使用して各タイプをチェックしてキャストする必要があります。

+0

構造型は最終的にはリフレクションによって実装されていませんか? 10億個のオブジェクトに対して '.toString'を使うことを心配している場合、リフレクションは同様のパフォーマンス上の懸念を持つかもしれません。 –

+0

@JonAndersonはい私はパフォーマンスがこれで問題であるのを見ることができました。ほとんどすべての入力にtoDoubleメソッドがない限り、構造的な型付けの懸念を脇に置いていても、例外のスロー/キャッチがたくさんあります。結局のところ、Scalaではこの問題に対する良い解決策はないと私は考えています。この機能が必要な場合は、動的言語を使用してください。私はあなたのソリューションは行く方法だと思っていますが、私は代替手段を提供するかもしれないと考えました。ここでのそれぞれの答えは、賛否両論が異なります。 – puhlen

-1

他にも良い回答があります。私がやったと思った別の方法は暗黙のオブジェクトを使うことでした。 、コンパイラの制約がImplicitTypeコンパニオンオブジェクト内の暗黙オブジェクトを利用できるからであるため、

sealed trait ImplicitType[T] 
object ImplicitType{ 
    implicit object IntType extends ImplicitType[Int] 
    implicit object StringType extends ImplicitType[String] 
    implicit object LongType extends ImplicitType[Long] 
    implicit object DoubleType extends ImplicitType[Double] 
} 

def toDouble[T : ImplicitType](n: T) : Option[Double] = { 
    Try(n.toString.toDouble).toOption 
} 

上記作品:あなたの上記の例では、あなたのような何かを書くことができます。コンテキスト境界暗黙のdef f:ImplicitType [T]は、デフォルトでコンパニオンオブジェクト内の暗黙オブジェクトをImplicitTypeで検索します。あなたのtoDouble機能は全く変わりません。このように

val foo = toDouble(1) // Some(1.0) 
val foo1 = toDouble("2") //Some(2.0) 
val foo2 = toDouble(1L) //Some(1.0) 
val foo3 = toDouble("s") //None 
val foo4 = toDouble(1.23456e300d) //Some(1.23456E300) 

:だから今のようなことを行うことができます。私はtoStringを避ける方法を考えることができませんでした。これはあなたのために働くことを望みます。

+0

これは、事前にタイプを知っている場合にのみ有効です。 OPは 'Any'で動作しています。これを行う場合は、toStringと例外からのオーバーヘッドを避けるために暗黙の型で 'toDouble'を実装するべきです。あなたの解決策は本質的にradumanolescuの答えと同じですが、 'Any'を受け入れる代わりに関数の型を制限します。 – puhlen

+0

良い点。私のこれは悪い –