Scala 中的动态提取器 [英] Dynamic Extractors in Scala

查看:21
本文介绍了Scala 中的动态提取器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不喜欢提取器的一件事是它们不能有参数.所以我不能有像 Param 这样的提取器:

One of the things I don't like about extractors is that they cannot have parameters. So I cannot have extractors like Param in:

req match { case Param("foo")(foo) => … }

动态提取器?

这很不幸,我希望有一天它会改变,但今天早上我想我可以通过使用 Dynamic trait 来修复它.

Dynamic Extractors?

That's unfortunate, and I hope it will change some day, but then this morning I figured I could fix it by using the Dynamic trait.

object Params extends Dynamic {
  def selectDynamic(name: String) = new {
    def unapply(params: Map[String, String]): Option[String] = params.get(name)
  }
}

...希望这能让我在这样的模式匹配语句中使用 Params:

… hoping that would allow me use Params in a pattern matching statement like this:

req match { case Params.Foo(value) => 
  // matching Map("Foo" -> "Bar"), extracting "Bar" in value

它不起作用

...但它不起作用.似乎编译器仍然感到困惑.

It doesn't work

… but it doesn't work. It seems the compiler is still getting confused.

scala> Map("Foo" -> "bar") match { case Params.Foo(value) => value }
<console>:10: error: value applyDynamic is not a member of object Params
error after rewriting to Params.<applyDynamic: error>("Foo")
possible cause: maybe a wrong Dynamic method signature?
              Map("Foo" -> "bar") match { case Params.Foo(value) => value }
                                               ^
<console>:10: error: not found: value value
              Map("Foo" -> "bar") match { case Params.Foo(value) => value }
                                                                    ^

我觉得很奇怪,因为

object Params {
  object Foo {
    def unapply{params: Map[String, String]): Option[String] = … 
  }
}

会很好用.另外,如果我先将 Params.Foo 分配给一个变量,一切都会好的:

would work fine. Also, if I assign Params.Foo to a variable first, everything is okay:

scala> val Foo = Params.Foo
Foo: AnyRef{def unapply(params: Map[String,String]): Option[String]} = Params$$anon$1@f2106d8

scala> Map("Foo" -> "bar") match { case Foo(value) => value }
warning: there were 1 feature warning(s); re-run with -feature for details
res2: String = bar

这应该被视为错误吗?

推荐答案

规范的答案是可以使用主体中的参数自定义提取器一个 case 语句(或其他任何可以使用提取器的地方)?

但是 黑客博客 提出了通过的技巧参数作为动态选择的任意名称,如问题中所尝试.

but the hacking blog suggests the trick of passing arguments as arbitrary names to dynamic selection, as tried in the question.

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.

scala> class X(pattern: String) { val RegExp = new { def unapplySeq(s: String) = pattern.r.unapplySeq(s) } }
defined class X

scala> import language._
import language._

scala> case object p extends Dynamic { def selectDynamic(pattern: String) = new X(pattern) }
defined object p

scala> "abcdef" match { case p.`.*(b.*d).*`.RegExp(s) => s }
res0: String = bcd

需要额外的选择,因为 2.11 中的崩溃错误与问题中显示的 2.10 错误不同:

The extra selection is required because of a crashing bug in 2.11 which is different from the 2.10 error shown in the question:

scala> class RegExp(pattern: String) { def unapplySeq(s: String) = pattern.r.unapplySeq(s) }
defined class RegExp

scala> case object p extends Dynamic { def selectDynamic(pattern: String) = new RegExp(pattern) }
defined object p

scala> "abcdef" match { case p.`.*(b.*d).*`(s) => s }
java.lang.NullPointerException
    at scala.tools.nsc.typechecker.PatternTypers$PatternTyper$class.inPlaceAdHocOverloadingResolution(PatternTypers.scala:68)

2.10 中的工作示例:

The working example in 2.10:

$ scala210 -language:_
Welcome to Scala version 2.10.5 (OpenJDK 64-Bit Server VM, Java 1.7.0_95).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :pa
// Entering paste mode (ctrl-D to finish)

class X(key: String) { val get = new { def unapply(params: Map[String, String]): Option[String] = params.get(key) }}
object Params extends Dynamic {
  def selectDynamic(name: String) = new X(name)
}

// Exiting paste mode, now interpreting.

defined class X
defined module Params

scala> Map("Foo" -> "bar") match { case Params.Foo.get(value) => value }
res0: String = bar

这与问题末尾显示的内容类似,但很明显可以通过这种方式使用动态选择.

This is similar to what is shown at the end of the question, but makes it obvious that dynamic selection can be used this way.

这篇关于Scala 中的动态提取器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆