【问题标题】:scala coding-style: initialize a val Seq depending on optional valuesscala 编码风格:根据可选值初始化 val Seq
【发布时间】:2012-05-31 03:08:33
【问题描述】:

我正在开发一个简单的函数,它应该基于可能不存在的可选参数构建一个 sql 条件。

我正在尝试使用不可变值以优雅和惯用的方式来完成它。

到目前为止,我得到了这样的东西:

val cond: Seq[String] = Nil ++ 
  (if (entity != "*") Seq("entity = {entity}") else Nil) ++
  (if (name != "*") Seq("name = {name}") else Nil) ++

val condition = 
  if (cond.size == 0) "" 
  else " where " + cond.mkString(" and ") + " "

所以,我只是合并 Seqs,如果值不存在,我会将它与 Nil 合并

使用 var 我得到类似的东西:

var cond: Seq[String] = Seq();
if (entity != "*") cond = cond :+ "entity = {entity}"
if (name != "*") cond = cond :+ "name = {name}"

我觉得它更具可读性(我想知道第二种方法是否因为 var 而不是线程安全的)

我想知道解决此类问题的 scala 惯用且优雅的方法是什么

--编辑

最后,我确定了这个实现:

val condition: String = {

  var cond: Seq[String] = Seq();

  if (entity != "") 
    cond = cond :+ "entity = {entity}"
  if (filter != "")
    cond = cond :+ """(name like {filter} or prev like {filter} or post like {filter})"""

  if (cond.size == 0) "" 
  else " where " + cond.mkString(" and ") + " "
}

【问题讨论】:

    标签: scala collections coding-style


    【解决方案1】:

    不要重复自己:

    def seqIf(r: String, s: String) = if (r != "*") Seq("%s = {%s}".format(s,s)) else Nil
    
    val cond = seqIf(entity, "entity") ++ seqIf(name, "name")
    

    不仅仅是字符串:

    def seqIf[A](p: Boolean, a: A) = if (p) Seq(a) else Nil
    
    val cond = seqIf(entity != "*", "entity = {entity}") ++ 
      seqIf(name != "*", "name = {name}")
    

    【讨论】:

    • 很好的提示,顺便说一句,你为什么要在一个单独的参数组中定义第二个参数,以便对函数进行柯里化?为什么要声明类型 [A]?
    • @opensas - 抱歉,打字很快,打算让它更通用。我会简化的。
    • @Rex - 如果在另一个测试中没有seqIf 的实例,为什么不这样定义:def seqIf(v: String, s: String) = if (v != "*") Seq("%s = {%s}".format(s,s)) else Nil
    • @Nicolas - 如果这真的是唯一的测试,我同意。
    • @Rex,嘿,我想看看更通用的版本,我仍然无法掌握 currying ;-)
    【解决方案2】:

    另一种方法是保留可变结构,但隐藏在块中以避免副作用:

    val cond = {
      var cs = Seq[String]()
      if (entity != "*") cs = cs :+ "entity = {entity}"
      if (name != "*") cs = cs :+ "name = {name}"
      cs
    }
    

    这样的结构是完全安全的,因为var 在块外是不可访问的。您还可以将 val 与可变构建器一起使用,例如 aListBuffer。在这种情况下。只要确保你没有将可变对象泄漏到块外:

    import scala.collection.mutable.ListBuffer
    
    val cond = {
      val cs = ListBuffer[String]()
      if (entity != "*") cs += "entity = {entity}"
      if (name != "*") cs += "name = {name}"
      cs.result() //Converts the ListBuffer into an immutable List
    }
    

    这是完全可以接受的,因为块本身仍然是“纯”的。这种模式出现在 Scala API 中。

    【讨论】:

    • 终于,var出现了! ;-) 进入 Scala 几个月,一直在努力为 var 找到可接受的用例
    • 很好的答案!!!和极好的提示!你能提供一个 Scala API 部分的链接吗?
    • 检查此文件是否有ListBuffer 出现:github.com/scala/scala/blob/v2.9.2/src/library/scala/collection/…
    • @virtualeyes Var 在 Akka 中也很有用,其中 Actor 状态必须是可变的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    相关资源
    最近更新 更多