我经常遇到将大多数可选的设置类对象转换为字符串或列表(例如转换为用于启动某些外部程序的参数)的问题。通常,我最终会得到与此类似的命令性代码:
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString = {
val args = new ArrayBuffer[String]()
if (host.nonEmpty) {
args+="--host"
args+=host.get
}
if (user.nonEmpty) {
args+="--user"
args+=user.get
}
if(password.nonEmpty) {
args+="--password"
args+=password.get
}
args mkString " "
}
}
是否有更类似于FP的方式?
答案 0 :(得分:5)
有几种方法。这应该起作用:
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString: String = {
host.map("--host " + _) ++
user.map("--user " + _) ++
password.map("--password " + _)
}.mkString(" ")
}
答案 1 :(得分:1)
还有另一种可能性,基于通过模式匹配过滤(collect
)的(参数名称,参数值)元组的列表:
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString(): String =
Seq(("host", host), ("user", user), ("password", password))
.collect { case (arg, Some(value)) => s"--$arg $value" }
.mkString(" ")
}
答案 2 :(得分:1)
借助Scala 2.13
,我们可以将概念推广到字段为Option[String]
的任何案例类:
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString(): String =
(productElementNames zip productIterator)
.collect { case (arg, Some(value)) => s"--$arg $value" }
.mkString(" ")
}
这是由于以下事实:使用Scala 2.13
,我们可以使用productElementNames
检索案例类的字段名称:
Options(Some("localhost"), None, Some("abcd")).productElementNames.toList
// List("host", "user", "password")
多亏了productIterator
,为案例类字段提供了压缩,这为我们提供了参数名称和值的迭代器:
Options(Some("localhost"), None, Some("abcd")).productIterator.toList
// List(Some(localhost), None, Some(abcd))
(productElementNames zip productIterator).toList
// List((host, Some("localhost")), (user, None), (password, Some("abcd")))
基于此,我们然后可以进行模式匹配以过滤出None
,并从过滤后的参数中得出一个字符串,以获得:
--host localhost --password abcd
答案 3 :(得分:0)
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString: String = {
Seq(
host.map("--host " + _),
user.map("--user " + _),
password.map("--password " + _)
)
.flatten
.mkString(" ")
}
}
答案 4 :(得分:0)
我会用类似的方法来处理它:
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def args: Seq[String] =
host.toList.flatMap(h => List("--host", h)) ++
user.toList.flatMap(u => List("--user", u)) ++
password.toList.flatMap(p => List("--password", p))
def argsString: String = args.mkString(" ")
}
我倾向于将构建的字符串移动到最外边缘,因为这意味着如果其他层想要操纵args,则不必拆分(或更糟地解析)构建的字符串。
答案 5 :(得分:0)
def argsString0 =
Array(s"${host.fold("")(e => s"--host ${e}")}",
s"${user.fold("")(e => s"--user ${e}")}",
s"${password.fold("")(e => s"--password ${e}")}").mkString(" ")
答案 6 :(得分:-1)
怎么样?
case class Options(host: Option[String], user: Option[String], password: Option[String]) {
def argsString =
List(
host.map(List("--host", _)),
user.map(List("--user", _)),
password.map(List("--password", _))
).flatten.flatten.mkString(" ")
}