Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.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
当方法尝试访问不存在的Case类成员时,Scala将执行隐式方法编译_Scala_Implicit_Scala Compiler - Fatal编程技术网

当方法尝试访问不存在的Case类成员时,Scala将执行隐式方法编译

当方法尝试访问不存在的Case类成员时,Scala将执行隐式方法编译,scala,implicit,scala-compiler,Scala,Implicit,Scala Compiler,我确实遇到了使用隐式方法的scala编译器问题。情况很简单。隐式方法的任务是将案例类A的对象转换为案例类B的对象。隐式方法实现访问不存在的案例类A的案例类成员。如果案例类A或B(例如foobar)中根本不存在案例类成员,编译器将抛出一个错误。如果案例类B中确实存在案例类成员,编译器不会抛出错误,即使我使用此名称访问案例类A(即成员x) 我在2.13.1版中使用Scala。目前,2.13.2是最新版本 下面的代码更详细地显示了该场景。以下代码将导致编译器错误 package Hokuspokus

我确实遇到了使用隐式方法的scala编译器问题。情况很简单。隐式方法的任务是将案例类A的对象转换为案例类B的对象。隐式方法实现访问不存在的案例类A的案例类成员。如果案例类A或B(例如foobar)中根本不存在案例类成员,编译器将抛出一个错误。如果案例类B中确实存在案例类成员,编译器不会抛出错误,即使我使用此名称访问案例类A(即成员x)

我在2.13.1版中使用Scala。目前,2.13.2是最新版本

下面的代码更详细地显示了该场景。以下代码将导致编译器错误

package Hokuspokus

object ImplicitMagic extends App {

  case class A(a: String, b: String, c: String)
  case class B(d: String, e: String, f: String, x: String)

  implicit def AtoB: A => B = a => B(a.a, a.b, a.c, a.foobar)

  def print(b: B): Unit = {
    System.out.println("Print" + b.d)
  }

  val a = A("foo", "bar", "asdf")

  print(a)

}
编译器声明以下错误:

[ERROR]   implicit def AtoB: A => B = a => B(a.a, a.b, a.c, a.foobar)
[ERROR]                                                       ^
[ERROR] one error found
但是,即使x不是case类的成员,以下代码也没有遇到编译器错误:

package Hokuspokus

object ImplicitMagic extends App {

  case class A(a: String, b: String, c: String)
  case class B(d: String, e: String, f: String, x: String)

  implicit def AtoB: A => B = a => B(a.a, a.b, a.c, a.x)

  def print(b: B): Unit = {
    System.out.println("Print" + b.d)
  }

  val a = A("foo", "bar", "asdf")

  print(a)

}
我现在想知道,为什么scala编译器在编译时没有检测到这个问题。为了理解scalac编译器的功能,我研究了编译后的scala类,但到目前为止我还没有得出结论

package Hokuspokus
object ImplicitMagic extends scala.AnyRef with scala.App {
  def this() = { /* compiled code */ }
  case class A(a: scala.Predef.String, b: scala.Predef.String, c: scala.Predef.String) extends scala.AnyRef with scala.Product with scala.Serializable {
    val a: scala.Predef.String = { /* compiled code */ }
    val b: scala.Predef.String = { /* compiled code */ }
    val c: scala.Predef.String = { /* compiled code */ }
    def copy(a: scala.Predef.String, b: scala.Predef.String, c: scala.Predef.String): Hokuspokus.ImplicitMagic.A = { /* compiled code */ }
    override def productPrefix: java.lang.String = { /* compiled code */ }
    def productArity: scala.Int = { /* compiled code */ }
    def productElement(x$1: scala.Int): scala.Any = { /* compiled code */ }
    override def productIterator: scala.collection.Iterator[scala.Any] = { /* compiled code */ }
    def canEqual(x$1: scala.Any): scala.Boolean = { /* compiled code */ }
    override def productElementName(x$1: scala.Int): java.lang.String = { /* compiled code */ }
    override def hashCode(): scala.Int = { /* compiled code */ }
    override def toString(): java.lang.String = { /* compiled code */ }
    override def equals(x$1: scala.Any): scala.Boolean = { /* compiled code */ }
  }
  object A extends scala.runtime.AbstractFunction3[scala.Predef.String, scala.Predef.String, scala.Predef.String, Hokuspokus.ImplicitMagic.A] with java.io.Serializable {
    def this() = { /* compiled code */ }
    final override def toString(): java.lang.String = { /* compiled code */ }
    def apply(a: scala.Predef.String, b: scala.Predef.String, c: scala.Predef.String): Hokuspokus.ImplicitMagic.A = { /* compiled code */ }
    def unapply(x$0: Hokuspokus.ImplicitMagic.A): scala.Option[scala.Tuple3[scala.Predef.String, scala.Predef.String, scala.Predef.String]] = { /* compiled code */ }
  }
  case class B(d: scala.Predef.String, e: scala.Predef.String, f: scala.Predef.String, x: scala.Predef.String) extends scala.AnyRef with scala.Product with scala.Serializable {
    val d: scala.Predef.String = { /* compiled code */ }
    val e: scala.Predef.String = { /* compiled code */ }
    val f: scala.Predef.String = { /* compiled code */ }
    val x: scala.Predef.String = { /* compiled code */ }
    def copy(d: scala.Predef.String, e: scala.Predef.String, f: scala.Predef.String, x: scala.Predef.String): Hokuspokus.ImplicitMagic.B = { /* compiled code */ }
    override def productPrefix: java.lang.String = { /* compiled code */ }
    def productArity: scala.Int = { /* compiled code */ }
    def productElement(x$1: scala.Int): scala.Any = { /* compiled code */ }
    override def productIterator: scala.collection.Iterator[scala.Any] = { /* compiled code */ }
    def canEqual(x$1: scala.Any): scala.Boolean = { /* compiled code */ }
    override def productElementName(x$1: scala.Int): java.lang.String = { /* compiled code */ }
    override def hashCode(): scala.Int = { /* compiled code */ }
    override def toString(): java.lang.String = { /* compiled code */ }
    override def equals(x$1: scala.Any): scala.Boolean = { /* compiled code */ }
  }
  object B extends scala.runtime.AbstractFunction4[scala.Predef.String, scala.Predef.String, scala.Predef.String, scala.Predef.String, Hokuspokus.ImplicitMagic.B] with java.io.Serializable {
    def this() = { /* compiled code */ }
    final override def toString(): java.lang.String = { /* compiled code */ }
    def apply(d: scala.Predef.String, e: scala.Predef.String, f: scala.Predef.String, x: scala.Predef.String): Hokuspokus.ImplicitMagic.B = { /* compiled code */ }
    def unapply(x$0: Hokuspokus.ImplicitMagic.B): scala.Option[scala.Tuple4[scala.Predef.String, scala.Predef.String, scala.Predef.String, scala.Predef.String]] = { /* compiled code */ }
  }
  implicit def AtoB: scala.Function1[Hokuspokus.ImplicitMagic.A, Hokuspokus.ImplicitMagic.B] = { /* compiled code */ }
  def print(b: Hokuspokus.ImplicitMagic.B): scala.Unit = { /* compiled code */ }
  val a: Hokuspokus.ImplicitMagic.A = { /* compiled code */ }
}

编译器正在执行多项操作以解决缺少的方法/val
a.foobar

它将检查此方法是否属于
案例类A
,它将检查A是否可以隐式转换为包含方法
foobar
的其他类型,或者是否存在添加方法
foobar
隐式类

最后,它决定此方法不可用,因此您会看到编译器错误

package Hokuspokus

object ImplicitMagic extends App {

  case class A(a: String, b: String, c: String)
  case class B(d: String, e: String, f: String, x: String)

  implicit def AtoB: A => B = a => B(a.a, a.b, a.c, a.foobar)

  def print(b: B): Unit = {
    System.out.println("Print" + b.d)
  }

  val a = A("foo", "bar", "asdf")

  print(a)

}
在使用
a.x
的情况下,编译器确实发现了从
a
B
的隐式转换,该转换提供了方法/val
x
。不幸的是,它没有捕捉到在实际转换中发生这种情况的事实。编译器在本例中所做的如下

implicit def AtoB: A => B = a => B(a.a, a.b, a.c, AtoB(a).x)

这会编译,但会在运行时生成StackOveflowException

非常感谢你的回答。编译器知道B有一个可用的x,因此他尝试将a.x的a再次转换为类型B,因为这是一个隐式方法,会导致堆栈溢出。这就解释了一切。@Joel这是一个很好的例子,说明了为什么隐式转换是不好的和不受欢迎的。在dotty中有效。还有编译器标志
-Wself implicit
,但似乎没有捕获它。@MarioGalic它似乎隐式转换也不能通过名称隐藏
implicit valf:Int=>String={implicit valf=null;implicit[Int=>String];=>“}
仍然可以编译,尽管
implicit vali:Int={implicit vali=null;implicit[Int];0}
不能编译。@DmytroMitin感谢分享。在第二种情况下,如果隐式值是一个简单类型,那么它正在工作,因为它没有编译,这是好的;在第一种情况下,如果隐式值是一个lambda函数,那么它正在编译,这是不好的。我认为这至少也是危险的,因为兰博达斯应该被视为语言的一等公民。