Предыдущий ответ будет работать, хотя он не охватывает все случаи. Например, цифры с суффиксом f
или d
могут анализироваться в Double или Float, как и некоторые строки, такие как "Infinity" или "-Infinity". Например, "12.1234567893901f".toFloat -> 12.123457
и "NaN".toFloat -> NaN
. Scientifi c или "E" нотация также разбирается в Float / Doubles (становится ±Infinity
при необходимости).
item.getClass
всегда будет String
в строка выше, поэтому сообщение об ошибке «Тип не поддерживается» может вводить в заблуждение, и вы можете предпочесть IllegalArgumentException
с сообщением, которое показывает item
вместо item.getClass
. - Проверка
s.toXXX.toString.equals(s)
выиграно ' t работает для значений s
, которые могут успешно анализироваться, но "не упрощены". Один случай - длинная цепочка цифр: "61234817390131412313458".toDouble.toString = "6.123481739013142E22"
. То же самое относится и к другим «не упрощенным» значениям, например, "+0".toFloat.toString = "0.0"
- . Как упоминалось в комментариях и предыдущих ответах, каждый метод
toXXX
может выдавать ошибку, поэтому, чтобы попробовать все из них, их можно обернуть в Try
. Метод find
для List
остановится и вернет первый элемент, который создает isSuccess
, равный true
. - Если
s.toFloat
не выдаст ошибку, то s.toDouble
не выдаст ошибку, и наоборот. Оба должны преуспеть или потерпеть неудачу вместе. Следовательно, необходимо выполнить дополнительные проверки, чтобы определить, какой из них более подходит (но, как уже упоминалось, toString.equals
слишком специфично c). - Определенные (очень положительные или отрицательные) значения становятся
±Infinity
при разборе на число с плавающей точкой, но не в два раза. Если ввод вводится в Infinity
для числа с плавающей запятой, но не в Double
, тогда вы можете предпочесть Double
. Если входной сигнал анализируется на Infinity
для обоих типов, выберите любой из них. - Слишком малые входы будут обнулены раньше для
Float
, чем для Double
.
Вот краткий обзор возможных определений функций:
object t {
type Result = (Int, Class[_])
type ListElt = (Result, String => Any)
def useFloat(s:String): Boolean = {
// determine if choosing Float is "desirable"
val floatVal:Float = s.toFloat
val doubleVal:Double = s.toDouble
// if very little precision is lost, or if the maximum information stored isn't lost completely
val MAX_LOST:Double = 1E-5.min(doubleVal)
val preservedPrecision:Boolean = (floatVal - doubleVal).abs <= MAX_LOST
// Remove this variable if `Double` is preferred when bothInfinite
val bothInfinite:Boolean = floatVal.isInfinite && doubleVal.isInfinite
preservedPrecision || bothInfinite
}
def getSizeAndType(s: String): Option[Result] = {
val floatResult:Result = (4, Float.getClass)
val doubleResult:Result = (8, Double.getClass)
val conversions: List[ListElt] = List(
((4, Int.getClass), ((x: String) => x.toInt)),
((8, Long.getClass), ((x: String) => x.toLong)),
(floatResult, ((x: String) => x.toFloat)),
(doubleResult, ((x: String) => x.toDouble)),
((1, Boolean.getClass), ((x: String) => x.toBoolean))
)
val firstSuccess: Option[ListElt] = conversions.find((elt: ListElt) => scala.util.Try(elt._2(s)).isSuccess)
val result = firstSuccess.map(_._1)
// check if choosing Float is "desirable"
result match {
case Some(`floatResult`) =>
if (useFloat(s)){
Some(floatResult)
} else {
Some(doubleResult)
}
case other => other
}
}
def handle(s:String) = {
val (bytes, arrayType) = getSizeAndType(s).getOrElse(0, "None")
if (bytes > 0) {
// perform allocation
//ByteBuffer.allocate(4 * array.length)
println(s"${bytes}, ${arrayType}")
} else {
// throw exception, etc.
println("Not parsable")
}
}
}
println(t.handle("9")) // 4, class scala.Int$
println(t.handle("1.9")) // 4, class scala.Float$
println(t.handle("2147483648")) // 8, class scala.Long$
println(t.handle("2.5769803776E9")) // 8, class scala.Double$ (small enough for finite float but loses enough precision)
println(t.handle("3.4028235E38")) // 8, class scala.Double$ (ditto)
println(t.handle("6.805647E38")) // 8, class scala.Double$ (too big for finite float)
println(t.handle("12.123456789")) // 4, class scala.Float$
println(t.handle("Infinity")) // 4, class scala.Float$
println(t.handle("false")) // 1, class scala.Boolean$
println(t.handle("xyz")) // Not parsable