涉及含义的“非法循环引用”的解释

问题描述 投票:2回答:1

在我的项目中,我有一个类型A,用于几个地方的参数,我想要一堆类型自动转换为该类型。我已经使用A的伴随对象中的一些隐式类来实现它。我删除了触发问题所不需要的一切:

trait A
object A {
  implicit class SeqA[T](v: Seq[T])(implicit x: T => A) extends A
  implicit class IntA(v: Int) extends A
  implicit class TupleA(v: (Int, Int)) extends SeqA(Seq(v._1, v._2))
}

但是scalac因为非法循环引用而拒绝此代码:

$ scalac -version
Scala compiler version 2.12.8 -- Copyright 2002-2018, LAMP/EPFL and Lightbend, Inc.
$ scalac A.scala 
A.scala:5: error: illegal cyclic reference involving class TupleA
  implicit class TupleA(v: (Int, Int)) extends SeqA(Seq(v._1, v._2))
                 ^
one error found

究竟是什么问题?什么是编译器绑定/推断/解决涉及非法循环?

奖励指向实现这些隐式类的有效方法。

scala implicit cyclic-reference
1个回答
4
投票

你正在遇到SI-9553,这是一个有三年半历史的编译器错误。

错误未修复的原因可能部分是因为有一个非常简单的解决方法 - 只需在您要扩展的泛型类上放置一个显式类型参数:

trait A
object A {
  implicit class SeqA[T](v: Seq[T])(implicit x: T => A) extends A
  implicit class IntA(v: Int) extends A
  implicit class TupleA(v: (Int, Int)) extends SeqA[Int](Seq(v._1, v._2))
}

无论如何,这可能是一个好主意,因为在任何涉及隐式定义的情况下,只要你输入类型参数,就会遇到麻烦。

作为旁注,您可以使用像-Xprint:typer这样的编译器选项来研究这样的问题。在这种情况下,它在REPL中显示以下内容:

// ...
implicit class TupleA extends $line6.$read.$iw.$iw.A.SeqA[Int] {
  <paramaccessor> private[this] val v: (Int, Int) = _;
  def <init>(v: (Int, Int)): $line6.$read.$iw.$iw.A.TupleA = {
    TupleA.super.<init>(scala.collection.Seq.apply[Int](v._1, v._2))({
      ((v: Int) => A.this.IntA(v))
    });
    ()
  }
};
implicit <synthetic> def <TupleA: error>(v: (Int, Int)): <error> = new TupleA(v)

在这种情况下,这不是非常有用,但它至少表明问题发生在TupleA隐式类的合成转换方法的定义中,而不是在此之前的某个时刻。

© www.soinside.com 2019 - 2024. All rights reserved.