Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 隐式参数赢得';我不能随便工作。如何对提取器隐藏无处不在的参数?_Scala_Pattern Matching_Implicit_Extractor - Fatal编程技术网

Scala 隐式参数赢得';我不能随便工作。如何对提取器隐藏无处不在的参数?

Scala 隐式参数赢得';我不能随便工作。如何对提取器隐藏无处不在的参数?,scala,pattern-matching,implicit,extractor,Scala,Pattern Matching,Implicit,Extractor,提取器对象中的unapply/unplyseq显然不支持隐式参数。假设这里有一个有趣的参数a,和一个令人不安的无处不在的参数b,在提取c时最好隐藏起来 [EDIT]:我的intellij/scala插件安装中似乎有什么东西被破坏了,导致了这种情况。我无法解释。最近我的智能有很多奇怪的问题。重新安装后,我无法再重新诊断我的问题。确认unapply/Unplyseq允许隐式参数!谢谢你的帮助 这不起作用(**编辑:是的,它起作用):** 在我对理想的提取器应该是什么样的理解中,Java人员也直观地了

提取器对象中的unapply/unplyseq显然不支持隐式参数。假设这里有一个有趣的参数a,和一个令人不安的无处不在的参数b,在提取c时最好隐藏起来

[EDIT]:我的intellij/scala插件安装中似乎有什么东西被破坏了,导致了这种情况。我无法解释。最近我的智能有很多奇怪的问题。重新安装后,我无法再重新诊断我的问题。确认unapply/Unplyseq允许隐式参数!谢谢你的帮助

这不起作用(**编辑:是的,它起作用):**

在我对理想的提取器应该是什么样的理解中,Java人员也直观地了解到它的意图,这种限制基本上禁止依赖于附加参数的提取器对象

您通常如何处理此限制?

到目前为止,我已经找到了四种可能的解决方案:

1) 我想改进的最简单的解决方案是:不要隐藏b,提供参数b和a,作为tuple形式的unapply的普通参数:

object A1{ 
    def unapply(a:(A,B)):Option[C] = Option(a._2.getC(a._1)) }
在客户端代码中:

 val c1 = (a,b) match { case A1(c) => c1 }
val bDeps = new BDependent(someB)
import bDeps.A2 
val a:A = ...
val c2 = a match { case A2(c) => c }
}
 val b:B = ...
 val soonAC: B => C = a match { case A4(x) => x }
 val d = soonAC(b).getD ...
我不喜欢它,因为这里有更多的噪音偏离,把a分解成c很重要。另外,由于java用户必须确信要实际使用这个scala代码,他们还面临着一个额外的合成新奇事物(元组大括号)。他们可能会受到反scala攻击“这是什么?…为什么不首先使用常规方法并检查是否?”

2) 在一个类中定义提取器,该类封装对某个特定实例的依赖关系,然后导入该实例的提取器。在导入站点,对于java用户来说有点不寻常,但在模式匹配站点b被很好地隐藏起来,并且直观地看到发生了什么。我最喜欢的。我错过了什么

class BDependent(b:B){ 
   object A2{ 
    def unapply(a:A):Option[C] = Option(b.getC(a))
         } }
客户端代码中的用法:

 val c1 = (a,b) match { case A1(c) => c1 }
val bDeps = new BDependent(someB)
import bDeps.A2 
val a:A = ...
val c2 = a match { case A2(c) => c }
}
 val b:B = ...
 val soonAC: B => C = a match { case A4(x) => x }
 val d = soonAC(b).getD ...
3) 在客户端代码的范围内声明提取器对象。b是隐藏的,因为它可以在本地范围内使用“b”。妨碍代码重用,严重污染客户端代码(此外,必须在代码使用之前声明)

4) 函数B=>C的have unapply return选项。这允许导入和使用一个与参数相关的通用提取器,而无需将B直接提供给提取器,而是在使用时提供给结果。Java用户可能会对函数值的使用感到困惑,b未隐藏:

 object A4{
  def unapply[A,C](a:A):Option[B => C] = Option((_:B).getC(a))
   }
然后在客户端代码中:

 val c1 = (a,b) match { case A1(c) => c1 }
val bDeps = new BDependent(someB)
import bDeps.A2 
val a:A = ...
val c2 = a match { case A2(c) => c }
}
 val b:B = ...
 val soonAC: B => C = a match { case A4(x) => x }
 val d = soonAC(b).getD ...
进一步评论:

  • 正如中所建议的,“视图边界”可能有助于提取器处理隐式转换,但这对隐式参数没有帮助。出于某种原因,我不喜欢使用隐式转换
  • 研究“上下文边界”,但它们似乎有相同的限制,不是吗

您的第一行代码在什么意义上不起作用?对于提取器方法的隐式参数列表,当然没有任意禁止

考虑以下设置(我使用普通的旧类而不是case类来显示这里没有额外的魔力):

现在,我们定义一个隐式
B
值,并使用
unapply
方法创建一个提取器对象:

implicit val b = new B("prefix: ")

object D {
  def unapply(a: A)(implicit b: B): Option[C] = Option(b getC a)
}
我们可以这样使用:

scala> val D(c) = new A(42)
c: C = C@52394fb3

scala> c.x
res0: String = prefix: 42

正如我们所预料的那样。我不明白为什么需要在这里解决问题。

问题在于隐式参数是编译时(静态)约束,而模式匹配是运行时(动态)方法

trait A; trait C; trait B { def getC(a: A): C }

object Extractor {
  def unapply(a: A)(implicit b: B): Option[C] = Some(b.getC(a))
}

// compiles (implicit is statically provided)
def withImplicit(a: A)(implicit b: B) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}

// does not compile
def withoutImplicit(a: A) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}
所以这是一个概念性的问题,解决方案取决于你真正想要实现什么。如果您想要沿着可选隐式的行进行操作,可以使用以下命令:

sealed trait FallbackNone {
  implicit object None extends Optional[Nothing] {
    def toOption = scala.None
  }
}
object Optional extends FallbackNone {
  implicit def some[A](implicit a: A) = Some(a)
  final case class Some[A](a: A) extends Optional[A] { 
    def toOption = scala.Some(a)
  }
}
sealed trait Optional[+A] { def toOption: Option[A]}
然后在您有
隐式b:b
的地方,您将有
隐式b:Optional[b]

object Extractor {
   def unapply(a:A)(implicit b: Optional[B]):Option[C] = 
      b.toOption.map(_.getC(a))
}

def test(a: A)(implicit b: Optional[B]) : Option[C] = a match { 
   case Extractor(c) => Some(c)
   case _            => None
}
以及以下两项:

test(new A {}) // None

{
  implicit object BImpl extends B { def getC(a: A) = new C {} }
  test(new A {}) // Some(...)
}

脚注:我知道这更多的是一个评论,而不是一个答案,但一个完整的工作示例不适合于一个评论。如果它不能回答问题,我很乐意删除。嗯!这将是个好消息。但是我很困惑。。。我已经为这个问题争论了好几天了。但是我的intellij/scala插件也有一些问题。试图在REPL中重现我的问题…换句话说,它实际上与提取器的概念无关,而是与隐式的静态性质有关。谢谢你的回答。我不太理解您的示例/解释:withoutImplicit()不需要编译,因为没有给出隐式。当然,我确实提供了一个,但我没有匹配或奇怪的ClassCastExceptions,例如,我的main不能被转换为空。也许这也与intellij安装中断有关。对不起,到目前为止,我无法在回复中重现错误。。。我很好奇,你能解释一下你所说的“可选隐式”是什么意思,以及你在最后三个列表中得到了什么吗?我不明白,抱歉……如果你想使用提取器时代码中总是有一个隐式可见,那么你就不需要可选的隐式,Travis的答案表明了这一点。我知道您希望能够使用提取器编译模式匹配,不管是否给出了这样的隐式。在这种情况下,您可以请求始终可用的
可选[B]
(它返回到
可选。如果未找到类型为
B
的基础隐式,则为None
)。啊,好的!现在我明白你的意思了。这可能在其他情况下派上用场。谢谢