【问题标题】:"With" statement equivalent for Scala?Scala 的“With”语句等效?
【发布时间】:2010-07-13 20:14:09
【问题描述】:

也许是 Scala 学习者的闲散思考,但是……在我的修补中,我写了以下内容:

( n.child.size > 0 ) && ( n.child.filter( ! _.isInstanceOf[Text] ).size == 0 )

('n' 是一个 scala.xml.Node,但这并不重要。具体的逻辑也不重要。)

调用 child() 两次不太好,所以我正要更改它:

val list = n.child
( list.size > 0 ) && ( list.filter( ! _.isInstanceOf[Text] ).size == 0 )

但是考虑到我非常感谢能够在不需要声明中间变量的情况下进行 filter() 和 map() 等操作,我立即发现这很糟糕。它是如此...如此...如此Java-ish! :p

唉,翻遍了 SO 和 Google 以及 ScalaDocs(尤其是 Any 和 AnyRef),而 The Book 没有找到任何合适的东西。我希望可能是这样的:

n.child{ list => ( list.size > 0 ) && ( list.filter( ! _.isInstanceOf[Text] ).size == 0 ) }

甚至

n.child.with{ list => ... }

这样的东西存在吗?还是我只是陷入了一种不可变的热情?

【问题讨论】:

  • 另外,过滤器/大小的东西效率低下。将其替换为 list.forall(_.isInstanceOf[Text])
  • 这就是我最初的想法,但它并不完全相同:我需要知道该列表仅包含 Text 元素并且是非空的。我刚刚发现 Iterable 的“计数”可以缩短一点:( n.child.size > 0 ) && ( n.child.count( ! _.isInstanceOf[Text] ) == 0 )
  • 更好:! (n.child.isEmpty || n.child.exists(!_.isInstanceOf[Text]))
  • 抱歉,不清楚。我的意思是 !n.child.isEmpty && n.child.forall(_.isInstanceof[Text]) 这与你通过德摩根定律的最后一个相同,而且 !x.exists(!y) 与 x 相同.forall(y)
  • 我遇到了同样的问题,但后来我了解到这种 val 的使用非常有益,并且无法与 java 的 mutable vars 相比。特别是如果您使用更好的名称,在本例中为“val child = n.child”,这会使代码更加明显。

标签: scala


【解决方案1】:
{
    import n.child._
    ( size > 0 ) && ( filter( ! _.isInstanceOf[Text] ).size == 0 )
}

【讨论】:

    【解决方案2】:

    “with”当然是 Scala 中的保留字,所以我们称它为“let”,来自 Lisp 和 Haskell 中类似的绑定形式。原来“let”只是写函数应用程序的一种倒退方式。

    def let[A,B](param:A)(body: A=>B):B = body(param)
    
    let(n.child){list=> ...}
    

    如果绑定变量只使用一次,当然可以使用匿名函数形式,但这与目的不符。

    【讨论】:

    • 不错!现在我有了一些新的 Scala 语法来解决问题。 :-)
    • 你也可以使用 pimp my library。
    • 不是和 "val list = n.child" "list..." 一样长吗?
    • 更准确地说,它相当于 {val list = n.child; list...},用大括号使其成为单个表达式。
    • 它应该在标准库中:)
    【解决方案3】:
    class Tap[A](underlying:A){
       def tap[B](func: A=>B) = func(underlying)
    }
    
    implicit def anyToTap[A](underlying:A)=new Tap(underlying)
    
    n.child.tap{x =>
       ( x.size > 0 ) &&
       ( x.filter( ! _.isInstanceOf[Text] ).size == 0 )
    }
    

    【讨论】:

    • 现在这个库中有一个 Tap 的实现:github.com/snowplow/scala-util
    • tap(A=>B) 方法可能应该是 tap(A=>Unit): A 以允许进一步的链接或分配,例如:val order = new Order().tap { o => o.setStatus('UNPAID') }
    【解决方案4】:

    如果你只是想限制中间变量的范围,你也可以在谓词周围创建一个块:

    val n = getNodeByMagic()
    val passesTest = {
        val child = n.child
        child.length == 0 && !child.filter(_.isInstanceOf[Text]).isEmpty
    }
    // child is not defined outside of the block
    

    【讨论】:

      【解决方案5】:

      您可以为此目的使用match

      n.child match {
      case list => ( list.size > 0 ) && ( list.filter( ! _.isInstanceOf[Text] ).size == 0 )
      }
      

      【讨论】:

        【解决方案6】:

        Scala 2.13开始,标准库现在提供了一个链式操作方法pipe正好适合这个需求:

        import scala.util.chaining._
        
        n.child.pipe(list => list.size > 0 && list.filterNot(_.isInstanceOf[Text]).size == 0)
        

        n.child 的值被“传送”到感兴趣的函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-01
          • 2012-12-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多