【问题标题】:how to expose test for a pattern match如何公开模式匹配的测试
【发布时间】:2010-09-11 08:52:38
【问题描述】:

我是 scala 的新手,但基本上已经找到了自己的方法......

在这里,我要求推荐/最佳实践/惯用的实现方式:

  • 在内部,MyClass 使用 state 类型,该类型由案例类的密封层次结构实现
  • 但在 API 上,只应公开一些布尔谓词,通过匹配(内部)状态来实现。

目前,我的实现是...

def isSane: Boolean = state match {
    case Ok(_,'valid) => true
    case _            => false
}

但是这个解决方案让我感觉很别扭,好像用 3 行代码表达的东西只有一行代码的信息内容。其实我想写的是:

def isSane: boolean = state matches Ok(_, 'valid)

可能/很可能在 scala 中自己实现一个合适的运算符,但在我研究之前,我想知道解决这个问题的通常方法是什么。也许还有一些现有的库实现?

【问题讨论】:

    标签: scala


    【解决方案1】:

    我会这样做:

    abstract class State {
      def matches(pf: PartialFunction[State, Unit]) = pf isDefinedAt this
    }
    
    // then
    
    def isSane = state matches { case Ok(_,'valid) => }
    

    因为matches 被定义为接收一个部分函数,​​所以您可以在它后面加上一个函数字面量,只包含应该为真的case 语句。你不需要返回任何东西,因为部分函数被定义为返回Unit。最后,matches 方法使用偏函数的isDefinedAt 方法来验证是否有case语句覆盖自己。

    【讨论】:

    • 是的,这确实是我的想法,以防有必要自己实现它......
    【解决方案2】:

    我可能老土了,但为什么不用多态呢?

    trait State { def sane: Boolean }
    
    trait InvalidState extends State { def sane = false }
    
    case class Ok(whatever: Whatever, s: Symbol) extends State {
       def sane = { s == 'valid }
    }
    
    case class Failure(msg: String) extends InvalidState 
    
    case class WarmingUp extends InvalidState
    
    // ...
    
    def isSane(): Boolean = state.sane
    

    当然,如果出于某种原因这不可能,您可以将Daniel's solution 概括一下:

    class Matcher[T](o: T) {
       def matches(pf: PartialFunction[T, Unit]) = pf isDefinedAt o
    }
    
    object Matcher {
       implicit def o2matcher[T](o: T): Matcher[T] = new Matcher(o)
    }
    
    // then
    def isSane = state matches { case Ok(_,'valid) => }
    

    【讨论】:

    • 在我看来State 不是sane 被调用的类,只是一个内部使用的类。
    • 一旦检查变得更加复杂,我就会选择经典的 OO 风格的解决方案。我不认为那是过时的,只是以我的可读性为标准。也就是说,如果基于模式匹配的解决方案可以写在一行中,并且可以立即传达我的意图,那么我更喜欢它而不是经典方法
    【解决方案3】:

    如果Symbol 属性静态已知为state 类型的属性:

    def isSane: Boolean =
      state.secondSymbolPropertyWhateverItsCalled == 'valid
    

    如果你不知道stateOk,那么:

    def isSane: Boolean =
      state.isInstanceOf[Ok] && state.asInstanceOf[Ok].symbolProp == 'valid
    

    但在这一点上,它并不比你写的更好。

    最后,您可以在该类型层次结构上定义 isSane 并委托给它:

    def isSane: Boolean =
      state.isSane
    

    【讨论】:

    • 在我想到的例子中,重点是真正匹配处于其中一种可能状态的某些属性。
    • 嗯...另一个有趣的问题是关于性能的。
    • ...我的猜测是编译器实际上会从原始模式匹配中生成类似于您的第二个示例的内容,而 OTOH,将 isSane 放入 State 层次结构将允许交换一些额外的存储空间可能会提高性能。但无论如何,在大多数情况下,考虑到当今系统的性能,这种细微差别并不重要
    猜你喜欢
    • 2016-10-07
    • 2022-10-22
    • 2020-02-25
    • 2021-10-11
    • 2014-10-06
    • 2017-02-08
    • 2019-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多