【发布时间】:2016-10-14 12:55:55
【问题描述】:
我有一个字符串列表,我想对每个项目进行几次转换。我想保留原始字符串,以便在它无效时显示它。示例如下:
import scala.util.Try
val list = List("<entry id='1'/>", "haha", "<entry id='hehe'/>")
def parseXML(str: String) = Try { xml.XML.loadString(str) }
list
.map(parseXML)
.map(tryEntry => tryEntry.map(entry => (entry \ "@id").text))
.map(tryId => tryId.flatMap(id => Try(id.toInt)))
// here I lose the original string
res17: List[Try[Int]] = List(
Success(1),
Failure(org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.),
Failure(java.lang.NumberFormatException: For input string: "hehe")
)
// here I keep a copy of the original string, so I can report the invalid entry to the user
list
.map(l => (l, parseXML(l)))
.map { case(line, tryEntry) => (line, tryEntry.map(entry => (entry \ "@id").text)) }
.map { case(line, tryId) => (line, tryId.flatMap(id => Try(id.toInt))) }
res19: List[(String, Try[Int])] = List(
("<entry id='1'/>", Success(1)),
("haha", Failure(org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.)),
("<entry id='hehe'/>", Failure(java.lang.NumberFormatException: For input string: "hehe"))
)
在res19中,我保留了原始字符串的副本,这样我可以报告错误和原始字符串。但是,我每次映射操作时都需要携带这些信息,这很丑陋。有没有更好的办法? (也许使用 ScalaZ State 和 for?)
【问题讨论】:
-
在第二条评论中,我认为“所以我不能举报”应该是“所以我可以举报”
-
谢谢@pascal-soucy,已修复。
-
我可能只是定义一个错误案例类,该类捕获底层异常和原始字符串。您将其映射到
parseXML中的失败端,然后像往常一样使用您的尝试。 -
是的,但我需要在
parseXML、id.toInt和许多其他地方这样做。太丑了。 -
@DavidPortabella 好吧,您可以使用
Writer(或或多或少等效于Tuple2[String, ?]的monad),它可以让您根据需要链接您的地图,但list.traverse(...)等不会没有正确的语义——你必须在排序之前兑现每个写入器操作。