【问题标题】:scala StackOverflow on implicit object unapply隐式对象中的scala堆栈溢出不适用
【发布时间】:2015-09-05 00:06:36
【问题描述】:

我正在编写一个类型类来在类型之间进行转换,我注意到隐式对象上的 unapply 方法有一些不寻常的地方。具体的

object IntString extends PartialFunction[String, Int] {
  def isDefinedAt(x: String) = Try(x.toInt).isSuccess
  def apply(v1: String) = v1.toInt
  def unapply(a:String):Option[Int] = if(this.isDefinedAt(a)) Some(this.apply(a)) else None
}

val s = "1000"
val IntString(i) = s

效果很好,但是

implicit object IntString extends PartialFunction[String, Int] {
  def isDefinedAt(x: String) = Try(x.toInt).isSuccess
  def apply(v1: String) = v1.toInt

  def unapply(a:String):Option[Int] = if(this.isDefinedAt(a)) Some(this.apply(a)) else None
}

val s = "1000"
val IntString(i) = s

apply 方法处提供 StackOverflow。我希望能够让对象是隐式的,这样我就可以做类似的事情

def parse[A,B](a:A)(implicit ev:PartialFunction[A,B]) = ev(a)

除了显式应用/取消应用。

【问题讨论】:

    标签: scala typeclass implicit


    【解决方案1】:

    apply 中的一切都出错了,特别是 v1.toIntjava.lang.String 没有 toInt 方法。它由StringLike 隐式提供。但是Int 有一个toInt 方法,并且您提供了从String => Int 的隐式转换。

    编译器发现您想在String 上调用toInt。编译器不是从StringLike 中选择丰富的方法,而是知道Int 有一个toInt 方法,并且您在范围内提供了一个隐式String => Int,所以它使用它。但是再次使用你的转换调用apply,它会无限重复这个过程。

    一个简单的解决方案是使用实际的类型类,而不是PartialFunction

    trait Conv[A, B] {
        def isDefinedAt(x: A): Boolean
        def apply(v1: A): B
        def unapply(a: A): Option[B]
    }
    
    implicit object IntString extends Conv[String, Int] {
    
      def isDefinedAt(x: String) = Try(x.toInt).isSuccess
    
      def apply(v1: String): Int = v1.toInt
    
      def unapply(a: String): Option[Int] =
        if(this.isDefinedAt(a)) Some(this.apply(a)) else None
    }
    
    scala> val IntString(i) = s
    i: Int = 1000
    

    你会将parse 更改为:

    def parse[A, B](a: A)(implicit ev: Conv[A,B]) = ev(a)
    

    【讨论】:

    • 谢谢!这是对正在发生的事情的非常清楚的解释。我以为发生了某种意想不到的隐含诡计,但我不确定是什么。我实际上想继续扩展PartialFunction(我的实际实现有一个扩展它的类型类),以便我可以在上面做orElseandThen之类的事情,但根据你的回答,我将v1.toInt更改为@987654344 @ 并且成功了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-18
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    • 2014-12-15
    • 2023-03-26
    相关资源
    最近更新 更多