删除对具有 Unit return 类型的函数的调用时发生奇怪的 Scala 编译器错误,这怎么可能?

Strange Scala compiler error when removing a call to a function that has Unit return type, how is this even possible?

这是一个奇怪的情况:

如果我在下面注释掉对 feed_usingExplicitTypeClassInstance 的调用,则会出现编译器错误。

很费解。 有什么解释吗?

我的意思是,我注释掉一个函数调用(return没有价值)然后代码就不再编译了?

这在理论上是否完全可行?在任何编程语言中?

我的意思是我注释掉了 println("hello") 这样的代码,然后代码就不再编译了?

当然,如果我注释掉一个声明什么的,但是对一个没有return任何东西的函数的调用,那当然是可以理解的?

object AnimalFeeder extends App {

  def feed_usingExplicitTypeClassInstance[AnimalInstance]
    (animalTypeClass: AnimalTypeClass[AnimalInstance])
    (food: animalTypeClass.FoodThatAnimalLikes) =
      {
          animalTypeClass.feed(food)
      }

  def feed_usingImplicitTypeClassInstance[AnimalInstance, Food]
    (food: Food)
    (implicit animalTypeClass: AnimalTypeClass.Aux[Food,AnimalInstance]) =
      {
        animalTypeClass.feed(food)
      }


  // If I comment out this line, THEN !, I get an error !!!! How ???
  feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())



  feed_usingImplicitTypeClassInstance(new CatFood)

}



trait Food {
  def eat(): Unit
}



trait AnimalTypeClass[AnimalInstance] {
  type FoodThatAnimalLikes <: Food
  def feed(f: FoodThatAnimalLikes) = f.eat()
}



object AnimalTypeClass {

  type Aux[Food, Animal] = AnimalTypeClass[Animal] {
    type FoodThatAnimalLikes = Food
  }

  implicit object CatInstance extends AnimalTypeClass[Cat] {
    override type FoodThatAnimalLikes = CatFood
  }

}


trait Cat

class CatFood extends Food {
  override def eat(): Unit = println("meow")
}

这是错误:

Error:(23, 38) could not find implicit value for parameter animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance]
  feed_usingImplicitTypeClassInstance(new CatFood)

Error:(23, 38) not enough arguments for method feed_usingImplicitTypeClassInstance: (implicit animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance])Unit.
Unspecified value parameter animalTypeClass.
  feed_usingImplicitTypeClassInstance(new CatFood)

编辑:

如果我插入行:

AnimalTypeClass.CatInstance

之前:

feed_usingImplicitTypeClassInstance(new CatFood)

然后代码再次编译,即使行

feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())

被注释掉了。

在使用该值后,您在同一个文件中定义了隐式值。当编译器在您调用 feed_usingImplicitTypeClassInstance 时查找隐式值时,它不会被初始化。使用对此隐式值的显式引用调用 feed_usingExplicitTypeClassInstance 会强制对隐式进行初始化,并且编译器可以在隐式调用中使用它。

可能的解决方案:

  • 将隐式值的定义移动到另一个文件。
  • 如果隐式值在同一个文件中,将其定义移到您隐式使用它的地方上方。

这是一个众所周知的问题,其中找不到在同一文件中使用后出现的隐式 并且没有显式类型注释 。出于这个原因,强烈建议(并且最终会强制执行)为所有非本地隐式提供显式类型注释。不幸的是,隐式对象在这里有点棘手,因为它们总是像没有类型注释的隐式定义一样,并且不可能给它们一个显式类型......但是最后我检查这似乎在 Dotty 中修复了隐式对象。

另请参阅 https://github.com/scala/bug/issues/8697

当您在代码中取消注释对 AnimalTypeClass.CatInstance 的调用时它确实起作用的原因是该引用将强制对隐式对象进行更早的类型检查,因此其类型将在其隐式使用之前已知.