【问题标题】:How to make implicit conversion work during pattern matching如何在模式匹配期间进行隐式转换
【发布时间】:2013-11-11 21:05:37
【问题描述】:

我有一个关键字和运算符的枚举(以及其他一些),例如(都是相似的):

object Keywords extends Enumeration {
    val AND, ARRAY, BEGIN, ...= Value

    case class Keyword(keyword: Value) extends Token[Value] {
        def this(keyword: String) = this(Keywords.fromString(keyword))
        def value = keyword
    }

    implicit def valueToKeyword(keyword: Value) = new Keyword(keyword)
}

这种隐式转换允许我在预期 Tokens 的地方传递枚举值,例如

def testFunction[T](t: Token[T]) = ...
testFunction(Keywords.ARRAY) // gets converted
testFunction(Operators.PLUS) // gets converted too

在匹配过程中似乎也没有应用相同的隐式转换,即

val token = new Keyword("ARRAY")
token match {
    case Keywords.ARRAY => ... // not selected but SHOULD be
    case Operators.PLUS => ... // completely different Enum
    ...
}

为什么?如何克服这个问题?

【问题讨论】:

    标签: scala enums implicit-conversion scala-2.10


    【解决方案1】:

    这不起作用,因为:

    token match {
      case Keywords.ARRAY => println("Array")
      case _ => println("Something else")
    }
    

    本质上是一个PartialFunction,具有以下类型签名:PartialFunction[Keywords.Value, Unit]。这意味着不会应用隐式,因为它要么是 isDefinedAt,要么不用于该输入。

    如果没有定义,case _ => ... 将捕获我的示例代码中的所有内容。如果它根本没有定义并且没有任何东西可以匹配它,那么你会得到一个 MatchError 抛出。

    在您的情况下,Token[Value] 类型的 token 未在匹配将编译到的部分函数中定义,因为仅定义了 Keywords.Value 的类型。

    三种解决方案

    如果你真的想要隐式,那么你可以明确地要求一个隐式(是的,那句话很有趣:))

    implicitly[Keywords.Value](token) match {
      case Keywords.ARRAY => println("Array")
      case _ => println("Something else")
    }
    

    或者您可以显式声明token 的类型,以调用隐式魔法:

    val token: Keywords.Value = new Keyword("ARRAY")
    token match {
      case Keywords.ARRAY => println("Array")
      case _ => println("Something else")
    }
    

    或者如果你可以没有隐含的生活,那么最简单的解决方案:

    token.value match {
      case Keywords.ARRAY => println("Array")
      case _ => println("Something else")
    }
    

    我知道这不是您要寻找的答案,但我希望您了解 match {...} 的真正含义以及偏函数是什么。

    【讨论】:

    • 谢谢。这些解决方案有些帮助,但是当我必须匹配真正不同的东西时呢?即令牌可以是 Token[Value] (== Keyword) 或 Token[Int] ( == IntegerLiteral )?
    • @AkosKrivachy 如何为Keyword 类定义一个match 方法,该方法将隐式转换为Keywords.Value?我尝试了something similar,但失败了。我不确定如何将case 块传递给这种方法。 match 方法的语法应该与常规 match 的语法相同并解决问题。
    • @Trylks 写你自己的match 并不能真正解决问题,但会创建不同的代码。由于您可以访问底层 result 值,因此不需要调用隐式。我修复了您的代码以使其正常工作:pastebin.com/EBPx0sGC 但您必须在调用它时显式使用a `match` { ... },因此这不是一个非常好的解决方案。还可以尝试注释掉隐式,我的示例代码将继续工作,所以这是一个不同的问题。
    • @AkosKrivachy 我明白了。我认为调用该方法时不需要反引号,仅在定义时才需要,所以是的,在语义和句法上不同的代码:/(你是对的,隐式用于任何常规用途,但它不适用于@987654350 `match` 不需要 @ 也不是。好消息:现在我知道什么是PartialFunction :) 非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多