如何将 Option[String] 转换为 Option[Int]?

8

我正在阅读和解析一个json文件。其中一个字段是可空的。它可能返回一个数字字符串,也可能返回Null。我需要将字符串转换为整数。我能够通过下面的代码从String转换为Option[Int],但无法从Option[String]转换为Option[Int]

 def toInt(userId: String):Option[Int] = {
  try {
    Some(userId.toInt)
  } catch {
    case e:Exception => None
  }
}

val user = toInt("abc")

我需要做哪些更改?


2
尝试(userId.toInt).toOption怎么样? - Infinity
5个回答

19
import util.Try

def toInt(o: Option[String]): Option[Int] =
  o.flatMap(s => Try(s.toInt).toOption)

示例:

scala> toInt(None)
res0: Option[Int] = None

scala> toInt(Some("42"))
res1: Option[Int] = Some(42)

scala> toInt(Some("abc"))
res2: Option[Int] = None

抱歉,我是Scala的新手。当我使用您的方法运行时,它可以正常工作。但是为什么以下调用会失败: scala> None.flatMap(s => Try(s.toInt).toOption) <console>:10: error: value toInt is not a member of Nothing None.flatMap(s => Try(s.toInt).toOption) - Madhur Bhaiya
以下代码对我有效:Try(o.getOrElse("").toInt).toOption。我使用的是Scala版本2.11。 - Madhur Bhaiya

6
Option(userId).map(_.toInt)

使用 Option 而不是 Some。然后使用 map 将其转换为 Int


3

Scala 2.13 引入了 String::toIntOption:

结合使用 flatMap,提供了一种从 Option[String] 安全转换为 Option[Int] 的方法:

Option("1").flatMap(_.toIntOption)            // Option[Int] = Some(1)
(None: Option[String]).flatMap(_.toIntOption) // Option[Int] = None
Option("abc").flatMap(_.toIntOption)          // Option[Int] = None
Option(null: String).flatMap(_.toIntOption)   // Option[Int] = None

1
你需要对Option进行map操作,以执行可能包含的值。在代码上下文中,我会使用flatMap,因为当前方法返回Option,所以我们必须展开嵌套的Option
def toInt(userIdOpt: Option[String]): Option[Int] = userIdOpt flatMap { userId =>
  try {
    Some(userId.toInt)
  } catch {
    case e:Exception => None
  }
}

scala> val u = Option("2")
u: Option[String] = Some(2)

scala> toInt(u)
res0: Option[Int] = Some(2)

scala> toInt(Some("a"))
res4: Option[Int] = None

我们可以使用Try来缩短这个代码。
import scala.util.Try

def toInt(userIdOpt: Option[String]): Option[Int] =
    userIdOpt.flatMap(a => Try(a.toInt).toOption)

Try(a.toInt) 返回一个Try[Int],其中成功的转换将是Success[Int],而失败的转换(不是整数)将是Failure[Throwable]Try 有一个非常方便的方法叫做toOption,它将把Success(a)转换为Some(a),而将Failure转换为None,这正是我们想要的。


1

@Chris Martin和@Michael Zajac提供的解决方案很有效:

import util.Try

def toInt(o: Option[String]): Option[Int] =
  o.flatMap(s => Try(s.toInt).toOption)

但是

如果输入数据经常不正确,则会通过 Try 增加 NumberFormatException 的产生,这对于垃圾收集器来说是不好的。 它需要在操作后使用更多的堆栈跟踪。这意味着我们应该尝试避免在此处使用 scala.util.Try

如果输入数据经常不正确,则以下解决方案不仅不短而且性能更佳:

def toInt(s: Option[String]): Option[Int] = s match {
  case None => None
  case Some(v) if v.isEmpty  => None
  case Some(v) => if (v.forall(_.isDigit) || (v.startsWith("-") && v.drop(1).forall(_.isDigit)))
    Some(v.toInt)
  else
    None
}

测试:

 scala>   toInt(None)
    res0: Option[Int] = None
 scala>   toInt(Some(""))
    res1: Option[Int] = None
 scala>   toInt(Some("42"))
    res2: Option[Int] = Some(42)
 scala>   toInt(Some("-42"))
    res3: Option[Int] = Some(-42)
 scala>   toInt(Some("abc"))
    res4: Option[Int] = None  

总结:永远不要使用异常来控制流程!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接